Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/core/MonoDevelop.Core')
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DefaultExecutionHandler.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionHandler.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/MonoPlatformExecutionHandler.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/NativePlatformExecutionHandler.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessAsyncOperation.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IProcessAsyncOperation.cs)33
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessHostController.cs81
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs43
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessWrapper.cs103
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/DefaultFileSystemExtension.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/Counter.cs52
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/InstrumentationConsumer.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/IInstrumentationConsumer.cs)14
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/InstrumentationService.cs98
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimeCounter.cs21
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimerCounter.cs11
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.LogReporting/CrashReporter.cs39
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedAsyncOperation.cs112
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedOperationMonitor.cs77
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedProgressMonitor.cs168
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AsyncOperation.cs134
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProgressMonitor.cs39
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProjectLoadProgressMonitor.cs11
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/FilteredProgressMonitor.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/NullAsyncOperation.cs73
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/NullProgressMonitor.cs242
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ProgressStatusMonitor.cs11
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ProjectLoadProgressMonitor.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/IProjectLoadProgressMonitor.cs)6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/SimpleProgressMonitor.cs77
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/SynchronizedProgressMonitor.cs139
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/WrappedProgressMonitor.cs103
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/SerializationContext.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml39
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj95
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs30
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/Gettext.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/IAsyncOperation.cs46
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/IProgressMonitor.cs82
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs51
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/Platform.cs26
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/ProgressMonitor.cs673
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs11
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectNode.cs77
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectSubtypeNode.cs214
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectTypeNode.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemNode.cs)32
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/FlavorTypeCondition.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/IPathHandler.cs)41
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/IFileFormat.cs7
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ISolutionItemHandler.cs5
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ItemTypeCondition.cs43
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/MSBuildProjectExtensionNode.cs46
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectBindingCodon.cs48
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectExtensionUtil.cs48
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectMigrationHandler.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IWorkspaceObject.cs)44
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectMigrationHandlerNode.cs45
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectModelExtensionNode.cs45
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs62
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemExtensionNode.cs64
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemHandler.cs23
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ItemTypeNode.cs)72
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1DotNetProjectHandler.cs44
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1FileFormat.cs102
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionEntityItemHandler.cs9
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionItemHandler.cs5
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/CompiledAssemblyProjectMSBuildHandler.cs68
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildImportProvider.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildProject.cs519
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildPropertySet.cs173
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildEvaluationContext.cs177
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildFileFormat.cs56
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildHandler.cs172
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImport.cs56
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItem.cs152
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItemGroup.cs73
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildObject.cs75
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs898
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectFromFile.cs324
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs2018
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs475
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProperty.cs259
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroup.cs415
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroupEvaluated.cs155
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroupMerged.cs234
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/RemoteProjectBuilder.cs159
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnData.cs141
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFile.cs581
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFileFormat.cs1017
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/UnknownSolutionItemTypeException.cs64
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/DotNetNamingPolicy.cs8
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyBag.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs149
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildExtension.cs34
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildHandler.cs139
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextEncoding.cs11
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildEventHandler.cs8
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildResult.cs13
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildTool.cs41
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ChainedExtension.cs94
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CleanEventHandler.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CombineEntryRenamedEventArgs.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs75
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ConfigurationEventHandler.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommand.cs56
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandCollection.cs18
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandExtension.cs101
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetAssemblyProject.cs108
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetCompilerParameters.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ConfigurationParameters.cs)14
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs510
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectBinding.cs76
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs61
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectExtension.cs132
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ExtensionChain.cs69
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProject.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProjectBinding.cs59
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IBuildTarget.cs14
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IDotNetLanguageBinding.cs5
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IMSBuildDataObject.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectParameters.cs)31
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IProject.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SimpleProjectItem.cs)25
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IProjectBinding.cs59
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IPropertySet.cs49
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemConfiguration.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/LanguageBindingService.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProjectFlavor.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProject.cs)70
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs1548
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConfiguration.cs88
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConvertTool.cs5
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs182
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs146
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItem.cs37
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemCollection.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemEventArgs.cs8
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectParameters.cs21
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectReference.cs189
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs341
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectServiceExtension.cs383
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterDotNetProject.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectBinding.cs)29
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectAttribute.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildExtension.cs)20
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectFlavorAttribute.cs48
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectModelExtensionAttribute.cs36
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterSolutionItemTypeAttribute.cs62
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs332
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfiguration.cs24
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfigurationSelector.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionEntityItem.cs584
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionExtension.cs89
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolder.cs265
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItem.cs549
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItemCollection.cs12
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs1859
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfiguration.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfigurationCollection.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemEventArgs.cs16
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemExtension.cs289
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemFactory.cs36
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemReference.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs63
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownSolutionItem.cs54
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownWorkspaceItem.cs20
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Workspace.cs130
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs347
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItemExtension.cs67
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs303
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectExtension.cs (renamed from main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProjectBinding.cs)62
162 files changed, 12529 insertions, 9904 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DefaultExecutionHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DefaultExecutionHandler.cs
index e56f71e714..7cac46b2a8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DefaultExecutionHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DefaultExecutionHandler.cs
@@ -37,7 +37,7 @@ namespace MonoDevelop.Core.Execution
return Runtime.ProcessService.GetDefaultExecutionHandler (command) != null;
}
- public IProcessAsyncOperation Execute (ExecutionCommand command, IConsole console)
+ public ProcessAsyncOperation Execute (ExecutionCommand command, IConsole console)
{
IExecutionHandler handler = Runtime.ProcessService.GetDefaultExecutionHandler (command);
return handler.Execute (command, console);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionHandler.cs
index da3985afa5..c4a2dd0790 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionHandler.cs
@@ -35,7 +35,7 @@ namespace MonoDevelop.Core.Execution
return command is DotNetExecutionCommand;
}
- public IProcessAsyncOperation Execute (ExecutionCommand command, IConsole console)
+ public ProcessAsyncOperation Execute (ExecutionCommand command, IConsole console)
{
DotNetExecutionCommand cmd = (DotNetExecutionCommand) command;
if (cmd.TargetRuntime == null)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs
index a0a1c7b6d0..fe12bceeb8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs
@@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
+using System.Threading;
namespace MonoDevelop.Core.Execution
{
@@ -56,6 +57,6 @@ namespace MonoDevelop.Core.Execution
/// <param name='console'>
/// Console where to log the output
/// </param>
- IProcessAsyncOperation Execute (ExecutionCommand command, IConsole console);
+ ProcessAsyncOperation Execute (ExecutionCommand command, IConsole console);
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/MonoPlatformExecutionHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/MonoPlatformExecutionHandler.cs
index a164a13508..42451c68f2 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/MonoPlatformExecutionHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/MonoPlatformExecutionHandler.cs
@@ -44,7 +44,7 @@ namespace MonoDevelop.Core.Execution
this.monoPath = monoPath;
}
- public override IProcessAsyncOperation Execute (ExecutionCommand command, IConsole console)
+ public override ProcessAsyncOperation Execute (ExecutionCommand command, IConsole console)
{
DotNetExecutionCommand dotcmd = (DotNetExecutionCommand) command;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/NativePlatformExecutionHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/NativePlatformExecutionHandler.cs
index 6783653e3a..8c429a80ae 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/NativePlatformExecutionHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/NativePlatformExecutionHandler.cs
@@ -45,7 +45,7 @@ namespace MonoDevelop.Core.Execution
this.defaultEnvironmentVariables = defaultEnvironmentVariables;
}
- public virtual IProcessAsyncOperation Execute (ExecutionCommand command, IConsole console)
+ public virtual ProcessAsyncOperation Execute (ExecutionCommand command, IConsole console)
{
ProcessExecutionCommand cmd = (ProcessExecutionCommand) command;
IDictionary<string, string> vars;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IProcessAsyncOperation.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessAsyncOperation.cs
index 977ea67c7c..1cdeadd47f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IProcessAsyncOperation.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessAsyncOperation.cs
@@ -29,25 +29,34 @@
using System;
using MonoDevelop.Core;
using MonoDevelop.Core.ProgressMonitoring;
+using System.Threading.Tasks;
+using System.Threading;
namespace MonoDevelop.Core.Execution
{
- public interface IProcessAsyncOperation: IAsyncOperation, IDisposable
+ public class ProcessAsyncOperation: AsyncOperation
{
- int ExitCode { get; }
+ protected ProcessAsyncOperation ()
+ {
+ }
+
+ public ProcessAsyncOperation (Task task, CancellationTokenSource cancellationTokenSource): base (task, cancellationTokenSource)
+ {
+ }
+
+ public int ExitCode { get; set; }
- int ProcessId { get; }
+ public int ProcessId { get; set; }
}
- public class NullProcessAsyncOperation : NullAsyncOperation, IProcessAsyncOperation
+ public class NullProcessAsyncOperation : ProcessAsyncOperation
{
- public NullProcessAsyncOperation (bool success) : base (success, false) {}
- public int ExitCode { get { return ((IAsyncOperation)this).Success? 0 : 1; } }
- public int ProcessId { get { return 0; } }
-
- void IDisposable.Dispose () {}
-
- public new static NullProcessAsyncOperation Success = new NullProcessAsyncOperation (true);
- public new static NullProcessAsyncOperation Failure = new NullProcessAsyncOperation (false);
+ public NullProcessAsyncOperation (int exitCode)
+ {
+ ExitCode = exitCode;
+ }
+
+ public static NullProcessAsyncOperation Success = new NullProcessAsyncOperation (0);
+ public static NullProcessAsyncOperation Failure = new NullProcessAsyncOperation (1);
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessHostController.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessHostController.cs
index 11be57b373..e22d48cba8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessHostController.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessHostController.cs
@@ -50,7 +50,7 @@ namespace MonoDevelop.Core.Execution
DateTime lastReleaseTime;
bool starting;
bool stopping;
- IProcessAsyncOperation process;
+ ProcessAsyncOperation process;
Timer timer;
string id;
IExecutionHandler executionHandlerFactory;
@@ -130,10 +130,10 @@ namespace MonoDevelop.Core.Execution
cmd.UserAssemblyPaths = userAssemblyPaths;
cmd.DebugMode = isDebugMode;
ProcessHostConsole cons = new ProcessHostConsole ();
- process = executionHandlerFactory.Execute (cmd, cons);
+ var p = process = executionHandlerFactory.Execute (cmd, cons);
Counters.ExternalHostProcesses++;
- process.Completed += ProcessExited;
+ process.Task.ContinueWith ((t) => ProcessExited (p));
} catch (Exception ex) {
if (tmpFile != null) {
@@ -155,7 +155,7 @@ namespace MonoDevelop.Core.Execution
}
}
- void ProcessExited (IAsyncOperation oper)
+ void ProcessExited (ProcessAsyncOperation oper)
{
lock (this) {
@@ -307,7 +307,7 @@ namespace MonoDevelop.Core.Execution
void WaitTimeout (object sender, System.Timers.ElapsedEventArgs args)
{
try {
- IProcessAsyncOperation oldProcess;
+ ProcessAsyncOperation oldProcess;
lock (this) {
if (references > 0) {
@@ -395,75 +395,4 @@ namespace MonoDevelop.Core.Execution
{
}
}
-
- class InernalProcessHost: Process, IProcessAsyncOperation
- {
- object doneLock = new object ();
- bool finished;
- OperationHandler completed;
-
- public InernalProcessHost ()
- {
- Exited += delegate {
- lock (doneLock) {
- finished = true;
- Monitor.PulseAll (doneLock);
- if (completed != null)
- completed (this);
- }
- };
- }
-
- public int ProcessId {
- get { return Id; }
- }
-
- public event OperationHandler Completed {
- add {
- lock (doneLock) {
- completed += value;
- if (finished)
- value (this);
- }
- }
- remove {
- lock (doneLock) {
- completed -= value;
- }
- }
- }
-
- public void Cancel ()
- {
- Kill ();
- }
-
- public void WaitForCompleted ()
- {
- lock (doneLock) {
- while (!finished)
- Monitor.Wait (doneLock);
- }
- }
-
- public bool IsCompleted {
- get {
- lock (doneLock) {
- return finished;
- }
- }
- }
-
- public bool Success {
- get {
- return true;
- }
- }
-
- public bool SuccessWithWarnings {
- get {
- return true;
- }
- }
- }
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs
index b88803792d..94e679d891 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs
@@ -155,15 +155,9 @@ namespace MonoDevelop.Core.Execution
// p.Exited += exited;
// p.EnableRaisingEvents = true;
- if (exited != null) {
- MonoDevelop.Core.OperationHandler handler = null;
- handler = delegate (MonoDevelop.Core.IAsyncOperation op) {
- op.Completed -= handler;
- exited (p, EventArgs.Empty);
- };
- ((MonoDevelop.Core.IAsyncOperation)p).Completed += handler;
- }
-
+ if (exited != null)
+ p.Task.ContinueWith (t => exited (p, EventArgs.Empty));
+
Counters.ProcessesStarted++;
p.Start ();
return p;
@@ -194,13 +188,13 @@ namespace MonoDevelop.Core.Execution
return startInfo;
}
- public IProcessAsyncOperation StartConsoleProcess (string command, string arguments, string workingDirectory, IConsole console,
+ public ProcessAsyncOperation StartConsoleProcess (string command, string arguments, string workingDirectory, IConsole console,
EventHandler exited)
{
return StartConsoleProcess (command, arguments, workingDirectory, null, console, exited);
}
- public IProcessAsyncOperation StartConsoleProcess (string command, string arguments, string workingDirectory,
+ public ProcessAsyncOperation StartConsoleProcess (string command, string arguments, string workingDirectory,
IDictionary<string, string> environmentVariables, IConsole console, EventHandler exited)
{
if ((console == null || (console is ExternalConsole)) && externalConsoleHandler != null) {
@@ -218,11 +212,8 @@ namespace MonoDevelop.Core.Execution
console != null ? !console.CloseOnDispose : false);
if (p != null) {
- if (exited != null) {
- p.Completed += delegate {
- exited (p, EventArgs.Empty);
- };
- }
+ if (exited != null)
+ p.Task.ContinueWith (t => exited (p, EventArgs.Empty));
Counters.ProcessesStarted++;
return p;
} else {
@@ -234,8 +225,8 @@ namespace MonoDevelop.Core.Execution
foreach (KeyValuePair<string, string> kvp in environmentVariables)
psi.EnvironmentVariables [kvp.Key] = kvp.Value;
ProcessWrapper pw = StartProcess (psi, console.Out, console.Error, null);
- new ProcessMonitor (console, pw, exited);
- return pw;
+ new ProcessMonitor (console, pw.ProcessAsyncOperation, exited);
+ return pw.ProcessAsyncOperation;
}
public IExecutionHandler GetDefaultExecutionHandler (ExecutionCommand command)
@@ -420,22 +411,22 @@ namespace MonoDevelop.Core.Execution
{
public IConsole console;
EventHandler exited;
- IProcessAsyncOperation operation;
+ ProcessAsyncOperation operation;
- public ProcessMonitor (IConsole console, IProcessAsyncOperation operation, EventHandler exited)
+ public ProcessMonitor (IConsole console, ProcessAsyncOperation operation, EventHandler exited)
{
this.exited = exited;
this.operation = operation;
this.console = console;
- operation.Completed += new OperationHandler (OnOperationCompleted);
- console.CancelRequested += new EventHandler (OnCancelRequest);
+ operation.Task.ContinueWith (t => OnOperationCompleted ());
+ console.CancelRequested += OnCancelRequest;
}
- public void OnOperationCompleted (IAsyncOperation op)
+ public void OnOperationCompleted ()
{
try {
if (exited != null)
- exited (op, null);
+ exited (operation, EventArgs.Empty);
if (!Platform.IsWindows && Mono.Unix.Native.Syscall.WIFSIGNALED (operation.ExitCode))
console.Log.WriteLine (GettextCatalog.GetString ("The application was terminated by a signal: {0}"), Mono.Unix.Native.Syscall.WTERMSIG (operation.ExitCode));
@@ -451,7 +442,7 @@ namespace MonoDevelop.Core.Execution
operation.Cancel ();
//remove the cancel handler, it will be attached again when StartConsoleProcess is called
- console.CancelRequested -= new EventHandler (OnCancelRequest);
+ console.CancelRequested -= OnCancelRequest;
}
}
@@ -475,5 +466,5 @@ namespace MonoDevelop.Core.Execution
}
}
- public delegate IProcessAsyncOperation ExternalConsoleHandler (string command, string arguments, string workingDirectory, IDictionary<string, string> environmentVariables, string title, bool pauseWhenFinished);
+ public delegate ProcessAsyncOperation ExternalConsoleHandler (string command, string arguments, string workingDirectory, IDictionary<string, string> environmentVariables, string title, bool pauseWhenFinished);
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessWrapper.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessWrapper.cs
index a5f121882e..2aa4f7d099 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessWrapper.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessWrapper.cs
@@ -2,36 +2,47 @@
using System;
using System.Threading;
using System.Diagnostics;
+using System.Threading.Tasks;
namespace MonoDevelop.Core.Execution
{
public delegate void ProcessEventHandler(object sender, string message);
[System.ComponentModel.DesignerCategory ("Code")]
- public class ProcessWrapper : Process, IProcessAsyncOperation
+ public class ProcessWrapper : Process
{
- private Thread captureOutputThread;
private Thread captureErrorThread;
ManualResetEvent endEventOut = new ManualResetEvent (false);
ManualResetEvent endEventErr = new ManualResetEvent (false);
bool done;
object lockObj = new object ();
+ Task task;
+ ProcessAsyncOperation operation;
+ IDisposable customCancelToken;
public ProcessWrapper ()
{
}
- public bool CancelRequested { get; private set; }
-
+ public bool CancelRequested { get; private set; }
+
+ public Task Task {
+ get { return task; }
+ }
+
+ public ProcessAsyncOperation ProcessAsyncOperation {
+ get { return operation; }
+ }
+
public new void Start ()
{
CheckDisposed ();
base.Start ();
-
- captureOutputThread = new Thread (new ThreadStart(CaptureOutput));
- captureOutputThread.Name = "Process output reader";
- captureOutputThread.IsBackground = true;
- captureOutputThread.Start ();
-
+
+ task = Task.Factory.StartNew (CaptureOutput, TaskCreationOptions.LongRunning);
+ var cs = new CancellationTokenSource ();
+ operation = new ProcessAsyncOperation (task, cs);
+ cs.Token.Register (Cancel);
+
if (ErrorStreamChanged != null) {
captureErrorThread = new Thread (new ThreadStart(CaptureError));
captureErrorThread.Name = "Process error reader";
@@ -40,6 +51,12 @@ namespace MonoDevelop.Core.Execution
} else {
endEventErr.Set ();
}
+ operation.ProcessId = Id;
+ }
+
+ public void SetCancellationToken (CancellationToken cancelToken)
+ {
+ customCancelToken = cancelToken.Register (Cancel);
}
public void WaitForOutput (int milliseconds)
@@ -56,6 +73,7 @@ namespace MonoDevelop.Core.Execution
private void CaptureOutput ()
{
+ Thread.CurrentThread.Name = "Process output reader";
try {
if (OutputStreamChanged != null) {
char[] buffer = new char [1024];
@@ -74,6 +92,9 @@ namespace MonoDevelop.Core.Execution
if (endEventErr != null)
endEventErr.WaitOne ();
+ if (HasExited)
+ operation.ExitCode = ExitCode;
+
OnExited (this, EventArgs.Empty);
lock (lockObj) {
@@ -108,9 +129,9 @@ namespace MonoDevelop.Core.Execution
return;
if (!done)
- ((IAsyncOperation)this).Cancel ();
+ Cancel ();
- captureOutputThread = captureErrorThread = null;
+ captureErrorThread = null;
endEventOut.Close ();
endEventErr.Close ();
endEventOut = endEventErr = null;
@@ -132,15 +153,7 @@ namespace MonoDevelop.Core.Execution
throw new ObjectDisposedException ("ProcessWrapper");
}
- int IProcessAsyncOperation.ExitCode {
- get { return ExitCode; }
- }
-
- int IProcessAsyncOperation.ProcessId {
- get { return Id; }
- }
-
- void IAsyncOperation.Cancel ()
+ public void Cancel ()
{
try {
if (!done) {
@@ -156,13 +169,12 @@ namespace MonoDevelop.Core.Execution
}
}
- void IAsyncOperation.WaitForCompleted ()
- {
- WaitForOutput ();
- }
-
void OnExited (object sender, EventArgs args)
{
+ if (customCancelToken != null) {
+ customCancelToken.Dispose ();
+ customCancelToken = null;
+ }
try {
if (!HasExited)
WaitForExit ();
@@ -171,49 +183,10 @@ namespace MonoDevelop.Core.Execution
} finally {
lock (lockObj) {
done = true;
- try {
- if (completedEvent != null)
- completedEvent (this);
- } catch {
- // Ignore
- }
}
}
}
- event OperationHandler IAsyncOperation.Completed {
- add {
- bool raiseNow = false;
- lock (lockObj) {
- if (done)
- raiseNow = true;
- else
- completedEvent += value;
- }
- if (raiseNow)
- value (this);
- }
- remove {
- lock (lockObj) {
- completedEvent -= value;
- }
- }
- }
-
- bool IAsyncOperation.Success {
- get { return done ? ExitCode == 0 : false; }
- }
-
- bool IAsyncOperation.SuccessWithWarnings {
- get { return false; }
- }
-
- bool IAsyncOperation.IsCompleted {
- get { return done; }
- }
-
- event OperationHandler completedEvent;
-
public event ProcessEventHandler OutputStreamChanged;
public event ProcessEventHandler ErrorStreamChanged;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/DefaultFileSystemExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/DefaultFileSystemExtension.cs
index c6667cd16b..ac77a0bb22 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/DefaultFileSystemExtension.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/DefaultFileSystemExtension.cs
@@ -97,7 +97,7 @@ namespace MonoDevelop.Core.FileSystem
public override void MoveDirectory (FilePath source, FilePath dest)
{
- Directory.Move (source, dest);
+ FileService.SystemDirectoryRename (source, dest);
}
public override void DeleteDirectory (FilePath path)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/Counter.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/Counter.cs
index 11ce9e69ad..5036c77e7a 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/Counter.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/Counter.cs
@@ -35,6 +35,7 @@ namespace MonoDevelop.Core.Instrumentation
{
internal int count;
int totalCount;
+ int lastStoredCount;
string name;
bool logMessages;
CounterCategory category;
@@ -45,8 +46,9 @@ namespace MonoDevelop.Core.Instrumentation
bool disposed;
bool storeValues;
bool enabled;
+ string id;
- List<IInstrumentationConsumer> handlers = new List<IInstrumentationConsumer> ();
+ List<InstrumentationConsumer> handlers = new List<InstrumentationConsumer> ();
public bool StoreValues {
get {
@@ -56,14 +58,22 @@ namespace MonoDevelop.Core.Instrumentation
storeValues = value;
}
}
+
+ public bool Enabled {
+ get { return enabled; }
+ }
- internal List<IInstrumentationConsumer> Handlers {
- get { return handlers; }
+ internal List<InstrumentationConsumer> Handlers {
+ get {
+ InstrumentationService.InitializeHandlers ();
+ return handlers;
+ }
}
internal void UpdateStatus ()
{
- enabled = InstrumentationService.Enabled || handlers.Count > 0;
+ InstrumentationService.InitializeHandlers ();
+ enabled = InstrumentationService.Enabled || Handlers.Count > 0;
storeValues = InstrumentationService.Enabled;
}
@@ -76,6 +86,11 @@ namespace MonoDevelop.Core.Instrumentation
public string Name {
get { return name; }
}
+
+ public string Id {
+ get { return id ?? Name; }
+ internal set { id = value; }
+ }
public CounterCategory Category {
get { return category; }
@@ -182,19 +197,29 @@ namespace MonoDevelop.Core.Instrumentation
}
}
- internal int StoreValue (string message, TimerTraceList traces)
+ internal int StoreValue (string message, TimeCounter timer)
{
DateTime now = DateTime.Now;
if (resolution.Ticks != 0) {
if (now - lastValueTime < resolution)
return -1;
}
- var val = new CounterValue (count, totalCount, now, message, traces);
+ var val = new CounterValue (count, totalCount, count - lastStoredCount, now, message, timer != null ? timer.TraceList : null);
+ lastStoredCount = count;
+
if (storeValues)
values.Add (val);
- if (handlers.Count > 0) {
- foreach (var h in handlers)
- h.ConsumeValue (this, val);
+ if (Handlers.Count > 0) {
+ if (timer != null) {
+ foreach (var h in handlers) {
+ var t = h.BeginTimer ((TimerCounter)this, val);
+ if (t != null)
+ timer.AddHandlerTracker (t);
+ }
+ } else {
+ foreach (var h in handlers)
+ h.ConsumeValue (this, val);
+ }
}
return values.Count - 1;
}
@@ -322,6 +347,7 @@ namespace MonoDevelop.Core.Instrumentation
{
int value;
int totalCount;
+ int change;
DateTime timestamp;
string message;
TimerTraceList traces;
@@ -335,15 +361,17 @@ namespace MonoDevelop.Core.Instrumentation
this.message = null;
traces = null;
threadId = 0;
+ change = 0;
}
- internal CounterValue (int value, int totalCount, DateTime timestamp, string message, TimerTraceList traces)
+ internal CounterValue (int value, int totalCount, int change, DateTime timestamp, string message, TimerTraceList traces)
{
this.value = value;
this.timestamp = timestamp;
this.totalCount = totalCount;
this.message = message;
this.traces = traces;
+ this.change = change;
this.threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
}
@@ -358,6 +386,10 @@ namespace MonoDevelop.Core.Instrumentation
public int TotalCount {
get { return totalCount; }
}
+
+ public int ValueChange {
+ get { return change; }
+ }
public int ThreadId {
get { return this.threadId; }
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/IInstrumentationConsumer.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/InstrumentationConsumer.cs
index 9f6af53387..8e0574fe64 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/IInstrumentationConsumer.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/InstrumentationConsumer.cs
@@ -28,10 +28,18 @@ using System;
namespace MonoDevelop.Core.Instrumentation
{
[Mono.Addins.TypeExtensionPoint]
- public interface IInstrumentationConsumer
+ public abstract class InstrumentationConsumer
{
- bool SupportsCounter (Counter counter);
- void ConsumeValue (Counter counter, CounterValue value);
+ public abstract bool SupportsCounter (Counter counter);
+
+ public virtual void ConsumeValue (Counter counter, CounterValue value)
+ {
+ }
+
+ public virtual IDisposable BeginTimer (TimerCounter counter, CounterValue value)
+ {
+ return null;
+ }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/InstrumentationService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/InstrumentationService.cs
index 0cbe2dccbb..bd9358bbac 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/InstrumentationService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/InstrumentationService.cs
@@ -54,7 +54,7 @@ namespace MonoDevelop.Core.Instrumentation
static Thread autoSaveThread;
static bool stopping;
static int autoSaveInterval;
- static List<IInstrumentationConsumer> handlers = new List<IInstrumentationConsumer> ();
+ static List<InstrumentationConsumer> handlers = new List<InstrumentationConsumer> ();
static bool handlersLoaded;
static InstrumentationService ()
@@ -64,12 +64,12 @@ namespace MonoDevelop.Core.Instrumentation
startTime = DateTime.Now;
}
- static void InitializeHandlers ()
+ internal static void InitializeHandlers ()
{
if (!handlersLoaded && AddinManager.IsInitialized) {
lock (counters) {
handlersLoaded = true;
- AddinManager.AddExtensionNodeHandler (typeof(IInstrumentationConsumer), HandleInstrumentationHandlerExtension);
+ AddinManager.AddExtensionNodeHandler (typeof(InstrumentationConsumer), HandleInstrumentationHandlerExtension);
}
}
}
@@ -84,26 +84,37 @@ namespace MonoDevelop.Core.Instrumentation
static void HandleInstrumentationHandlerExtension (object sender, ExtensionNodeEventArgs args)
{
- var handler = (IInstrumentationConsumer)args.ExtensionObject;
+ var handler = (InstrumentationConsumer)args.ExtensionObject;
if (args.Change == ExtensionChange.Add) {
- handlers.Add (handler);
- lock (counters) {
- foreach (var c in counters.Values) {
- if (handler.SupportsCounter (c))
- c.Handlers.Add (handler);
- }
- }
+ RegisterInstrumentationConsumer (handler);
}
else {
- handlers.Remove (handler);
- lock (counters) {
- foreach (var c in counters.Values)
- c.Handlers.Remove (handler);
+ UnregisterInstrumentationConsumer (handler);
+ }
+ }
+
+ public static void RegisterInstrumentationConsumer (InstrumentationConsumer consumer)
+ {
+ lock (counters) {
+ handlers.Add (consumer);
+ foreach (var c in counters.Values) {
+ if (consumer.SupportsCounter (c))
+ c.Handlers.Add (consumer);
}
}
UpdateCounterStatus ();
}
+ public static void UnregisterInstrumentationConsumer (InstrumentationConsumer consumer)
+ {
+ lock (counters) {
+ handlers.Remove (consumer);
+ foreach (var c in counters.Values)
+ c.Handlers.Remove (consumer);
+ }
+ UpdateCounterStatus ();
+ }
+
public static int PublishService ()
{
RemotingService.RegisterRemotingChannel ();
@@ -123,7 +134,7 @@ namespace MonoDevelop.Core.Instrumentation
throw new InvalidOperationException ("Service not published");
if (Platform.IsMac) {
- var macOSDir = PropertyService.EntryAssemblyPath.ParentDirectory.ParentDirectory.ParentDirectory;
+ var macOSDir = PropertyService.EntryAssemblyPath.ParentDirectory.ParentDirectory.ParentDirectory.ParentDirectory.Combine ("MacOS");
var app = macOSDir.Combine ("MDMonitor.app");
if (Directory.Exists (app)) {
var psi = new ProcessStartInfo ("open", string.Format ("-n '{0}' --args -c localhost:{1} ", app, publicPort)) {
@@ -223,10 +234,15 @@ namespace MonoDevelop.Core.Instrumentation
public static Counter CreateCounter (string name, string category, bool logMessages)
{
- return CreateCounter (name, category, logMessages, false);
+ return CreateCounter (name, category, logMessages, null, false);
}
- static Counter CreateCounter (string name, string category, bool logMessages, bool isTimer)
+ public static Counter CreateCounter (string name, string category = null, bool logMessages = false, string id = null)
+ {
+ return CreateCounter (name, category, logMessages, id, false);
+ }
+
+ static Counter CreateCounter (string name, string category, bool logMessages, string id, bool isTimer)
{
InitializeHandlers ();
@@ -241,6 +257,7 @@ namespace MonoDevelop.Core.Instrumentation
}
Counter c = isTimer ? new TimerCounter (name, cat) : new Counter (name, cat);
+ c.Id = id;
c.LogMessages = logMessages;
cat.AddCounter (c);
@@ -289,7 +306,12 @@ namespace MonoDevelop.Core.Instrumentation
public static TimerCounter CreateTimerCounter (string name, string category, double minSeconds, bool logMessages)
{
- TimerCounter c = (TimerCounter) CreateCounter (name, category, logMessages, true);
+ return CreateTimerCounter (name, category, minSeconds, logMessages, null);
+ }
+
+ public static TimerCounter CreateTimerCounter (string name, string category = null, double minSeconds = 0, bool logMessages = false, string id = null)
+ {
+ TimerCounter c = (TimerCounter) CreateCounter (name, category, logMessages, id, true);
c.DisplayMode = CounterDisplayMode.Line;
c.LogMessages = logMessages;
c.MinSeconds = minSeconds;
@@ -357,7 +379,7 @@ namespace MonoDevelop.Core.Instrumentation
}
}
- public static IProgressMonitor GetInstrumentedMonitor (IProgressMonitor monitor, TimerCounter counter)
+ public static ProgressMonitor GetInstrumentedMonitor (ProgressMonitor monitor, TimerCounter counter)
{
if (enabled) {
AggregatedProgressMonitor mon = new AggregatedProgressMonitor (monitor);
@@ -368,37 +390,23 @@ namespace MonoDevelop.Core.Instrumentation
}
}
- class IntrumentationMonitor: NullProgressMonitor
+ class IntrumentationMonitor: ProgressMonitor
{
TimerCounter counter;
Stack<ITimeTracker> timers = new Stack<ITimeTracker> ();
- LogTextWriter logger = new LogTextWriter ();
-
+
public IntrumentationMonitor (TimerCounter counter)
{
this.counter = counter;
- logger.TextWritten += HandleLoggerTextWritten;
}
- void HandleLoggerTextWritten (string writtenText)
+ protected override void OnWriteLog (string message)
{
if (timers.Count > 0)
- timers.Peek ().Trace (writtenText);
- }
-
- public override void BeginTask (string name, int totalWork)
- {
- if (!string.IsNullOrEmpty (name)) {
- ITimeTracker c = counter.BeginTiming (name);
- c.Trace (name);
- timers.Push (c);
- } else {
- timers.Push (null);
- }
- base.BeginTask (name, totalWork);
+ timers.Peek ().Trace (message);
}
-
- public override void BeginStepTask (string name, int totalWork, int stepSize)
+
+ protected override void OnBeginTask (string name, int totalWork, int stepWork)
{
if (!string.IsNullOrEmpty (name)) {
ITimeTracker c = counter.BeginTiming (name);
@@ -407,23 +415,15 @@ namespace MonoDevelop.Core.Instrumentation
} else {
timers.Push (null);
}
- base.BeginStepTask (name, totalWork, stepSize);
}
- public override void EndTask ()
+ protected override void OnEndTask (string name, int totalWork, int stepWork)
{
if (timers.Count > 0) {
ITimeTracker c = timers.Pop ();
if (c != null)
c.End ();
}
- base.EndTask ();
- }
-
- public override System.IO.TextWriter Log {
- get {
- return logger;
- }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimeCounter.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimeCounter.cs
index 140f84f899..55227a859f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimeCounter.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimeCounter.cs
@@ -25,6 +25,7 @@
// THE SOFTWARE.
using System;
+using System.Collections.Generic;
namespace MonoDevelop.Core.Instrumentation
{
@@ -55,6 +56,7 @@ namespace MonoDevelop.Core.Instrumentation
TimerTraceList traceList;
TimerTrace lastTrace;
TimerCounter counter;
+ object linkedTrackers;
internal TimeCounter (TimerCounter counter)
{
@@ -62,6 +64,18 @@ namespace MonoDevelop.Core.Instrumentation
traceList = new TimerTraceList ();
Begin ();
}
+
+ public void AddHandlerTracker (IDisposable t)
+ {
+ if (linkedTrackers == null)
+ linkedTrackers = t;
+ else if (!(linkedTrackers is List<IDisposable>)) {
+ var list = new List<IDisposable> ();
+ list.Add ((IDisposable)linkedTrackers);
+ list.Add (t);
+ } else
+ ((List<IDisposable>)linkedTrackers).Add (t);
+ }
internal TimerTraceList TraceList {
get { return this.traceList; }
@@ -98,6 +112,13 @@ namespace MonoDevelop.Core.Instrumentation
else
counter.AddTime (traceList.TotalTime);
counter = null;
+
+ if (linkedTrackers is List<IDisposable>) {
+ foreach (var t in (List<IDisposable>)linkedTrackers)
+ t.Dispose ();
+ } else if (linkedTrackers != null)
+ ((IDisposable)linkedTrackers).Dispose ();
+
}
void IDisposable.Dispose ()
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimerCounter.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimerCounter.cs
index ed2f54cd46..316d54f87e 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimerCounter.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Instrumentation/TimerCounter.cs
@@ -82,7 +82,7 @@ namespace MonoDevelop.Core.Instrumentation
public override void Trace (string message)
{
- if (InstrumentationService.Enabled) {
+ if (Enabled) {
if (lastTimer != null)
lastTimer.Trace (message);
else {
@@ -103,13 +103,14 @@ namespace MonoDevelop.Core.Instrumentation
public ITimeTracker BeginTiming (string message)
{
ITimeTracker timer;
- if (!InstrumentationService.Enabled) {
+ if (!Enabled) {
timer = dummyTimer;
} else {
+ var c = new TimeCounter (this);
lock (values) {
- timer = lastTimer = new TimeCounter (this);
+ timer = lastTimer = c;
count++;
- int i = StoreValue (message, lastTimer.TraceList);
+ int i = StoreValue (message, lastTimer);
lastTimer.TraceList.ValueIndex = i;
}
}
@@ -120,7 +121,7 @@ namespace MonoDevelop.Core.Instrumentation
public void EndTiming ()
{
- if (InstrumentationService.Enabled && lastTimer != null)
+ if (Enabled && lastTimer != null)
lastTimer.End ();
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.LogReporting/CrashReporter.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.LogReporting/CrashReporter.cs
new file mode 100644
index 0000000000..96b3c6e313
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.LogReporting/CrashReporter.cs
@@ -0,0 +1,39 @@
+//
+// CrashReporter.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using Mono.Addins;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Core.LogReporting
+{
+ [TypeExtensionPoint]
+ public abstract class CrashReporter
+ {
+ public abstract void ReportCrash (Exception ex, bool willShutDown, IEnumerable<string> tags);
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedAsyncOperation.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedAsyncOperation.cs
deleted file mode 100644
index b4067d2923..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedAsyncOperation.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// AggregatedAsyncOperation.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-
-namespace MonoDevelop.Core.ProgressMonitoring
-{
- public class AggregatedAsyncOperation: IAsyncOperation
- {
- public event OperationHandler Completed;
-
- List<IAsyncOperation> operations = new List<IAsyncOperation> ();
- bool started;
- bool success = true;
- bool successWithWarnings = true;
- int completed;
-
- public void Add (IAsyncOperation oper)
- {
- if (started)
- throw new InvalidOperationException ("Can't add more operations after calling StartMonitoring");
- operations.Add (oper);
- }
-
- public void StartMonitoring ()
- {
- started = true;
- foreach (IAsyncOperation oper in operations)
- oper.Completed += OperCompleted;
- }
-
- void OperCompleted (IAsyncOperation op)
- {
- bool raiseEvent;
- lock (operations) {
- completed++;
- success = success && op.Success;
- successWithWarnings = success && op.SuccessWithWarnings;
- raiseEvent = (completed == operations.Count);
- }
- if (raiseEvent && Completed != null)
- Completed (this);
- }
-
- public void Cancel ()
- {
- CheckStarted ();
- lock (operations) {
- foreach (IAsyncOperation op in operations)
- op.Cancel ();
- }
- }
-
- public void WaitForCompleted ()
- {
- CheckStarted ();
- foreach (IAsyncOperation op in operations)
- op.WaitForCompleted ();
- }
-
- public bool IsCompleted {
- get {
- CheckStarted ();
- return completed == operations.Count;
- }
- }
-
- public bool Success {
- get {
- CheckStarted ();
- return success;
- }
- }
-
- public bool SuccessWithWarnings {
- get {
- CheckStarted ();
- return successWithWarnings;
- }
- }
-
- void CheckStarted ()
- {
- if (!started)
- throw new InvalidOperationException ("Operation not started");
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedOperationMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedOperationMonitor.cs
deleted file mode 100644
index c8ffc6fa50..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedOperationMonitor.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// AggregatedOperationMonitor.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-
-using System;
-using System.Collections.Generic;
-
-namespace MonoDevelop.Core.ProgressMonitoring
-{
- public class AggregatedOperationMonitor: IDisposable
- {
- List<IAsyncOperation> list = new List<IAsyncOperation> ();
- IProgressMonitor monitor;
-
- public AggregatedOperationMonitor (IProgressMonitor monitor, params IAsyncOperation[] operations)
- {
- this.monitor = monitor;
-
- if (operations != null) {
- lock (list) {
- foreach (IAsyncOperation operation in operations)
- AddOperation (operation);
- }
- }
-
- monitor.CancelRequested += new MonitorHandler (OnCancel);
- }
-
- public void AddOperation (IAsyncOperation operation)
- {
- lock (list) {
- if (monitor.IsCancelRequested)
- operation.Cancel ();
- else
- list.Add (operation);
- }
- }
-
- void OnCancel (IProgressMonitor m)
- {
- lock (list) {
- foreach (IAsyncOperation operation in list)
- operation.Cancel ();
- }
- }
-
- public void Dispose ()
- {
- monitor.CancelRequested -= new MonitorHandler (OnCancel);
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedProgressMonitor.cs
index cd8c4aed7b..6bf2638e99 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedProgressMonitor.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AggregatedProgressMonitor.cs
@@ -30,6 +30,8 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Threading.Tasks;
+using System.Threading;
namespace MonoDevelop.Core.ProgressMonitoring
{
@@ -48,179 +50,145 @@ namespace MonoDevelop.Core.ProgressMonitoring
All = 0xff
}
- public class AggregatedProgressMonitor: IProgressMonitor, IAsyncOperation
+ public class AggregatedProgressMonitor: ProgressMonitor
{
- IProgressMonitor masterMonitor;
+ ProgressMonitor masterMonitor;
List<MonitorInfo> monitors = new List<MonitorInfo> ();
- LogTextWriter logger;
+ CancellationTokenSource cancelSource;
class MonitorInfo {
public MonitorAction ActionMask;
- public IProgressMonitor Monitor;
+ public ProgressMonitor Monitor;
+ public CancellationTokenRegistration CancellationTokenRegistration;
}
- public IProgressMonitor MasterMonitor {
+ public ProgressMonitor MasterMonitor {
get { return this.masterMonitor; }
}
- public AggregatedProgressMonitor (): this (new NullProgressMonitor ())
+ public AggregatedProgressMonitor (): this (new ProgressMonitor ())
{
}
- public AggregatedProgressMonitor (IProgressMonitor masterMonitor, params IProgressMonitor[] slaveMonitors)
+ public AggregatedProgressMonitor (ProgressMonitor masterMonitor, params ProgressMonitor[] slaveMonitors): this (masterMonitor, null, slaveMonitors)
{
+ }
+
+ internal AggregatedProgressMonitor (ProgressMonitor masterMonitor, CancellationTokenSource cancelSource, params ProgressMonitor[] slaveMonitors)
+ {
+ this.cancelSource = cancelSource ?? new CancellationTokenSource ();
this.masterMonitor = masterMonitor;
AddSlaveMonitor (masterMonitor, MonitorAction.All);
- logger = new LogTextWriter ();
- logger.TextWritten += new LogTextEventHandler (OnWriteLog);
- foreach (IProgressMonitor mon in slaveMonitors)
+ foreach (ProgressMonitor mon in slaveMonitors)
AddSlaveMonitor (mon);
}
- public void AddSlaveMonitor (IProgressMonitor slaveMonitor)
+ public new void AddSlaveMonitor (ProgressMonitor slaveMonitor)
{
AddSlaveMonitor (slaveMonitor, MonitorAction.All);
}
- public void AddSlaveMonitor (IProgressMonitor slaveMonitor, MonitorAction actionMask)
+ public void AddSlaveMonitor (ProgressMonitor slaveMonitor, MonitorAction actionMask)
{
MonitorInfo smon = new MonitorInfo ();
smon.ActionMask = actionMask;
smon.Monitor = slaveMonitor;
monitors.Add (smon);
if ((actionMask & MonitorAction.SlaveCancel) != 0)
- slaveMonitor.CancelRequested += new MonitorHandler (OnSlaveCancelRequested);
+ smon.CancellationTokenRegistration = slaveMonitor.CancellationToken.Register (OnSlaveCancelRequested);
}
-
- public void BeginTask (string name, int totalWork)
+
+ protected override void OnBeginTask (string name, int totalWork, int stepWork)
{
- foreach (MonitorInfo info in monitors)
- if ((info.ActionMask & MonitorAction.Tasks) != 0)
- info.Monitor.BeginTask (name, totalWork);
+ if (stepWork == -1) {
+ foreach (MonitorInfo info in monitors)
+ if ((info.ActionMask & MonitorAction.Tasks) != 0)
+ info.Monitor.BeginTask (name, totalWork);
+ } else {
+ foreach (MonitorInfo info in monitors)
+ if ((info.ActionMask & MonitorAction.Tasks) != 0) {
+ info.Monitor.BeginStep (stepWork);
+ info.Monitor.BeginTask (name, totalWork);
+ }
+ }
}
-
- public void BeginStepTask (string name, int totalWork, int stepSize)
+
+ protected override void OnEndTask (string name, int totalWork, int stepWork)
{
foreach (MonitorInfo info in monitors)
if ((info.ActionMask & MonitorAction.Tasks) != 0)
- info.Monitor.BeginStepTask (name, totalWork, stepSize);
+ info.Monitor.EndTask ();
}
-
- public void EndTask ()
+
+ protected override void OnStep (string message, int work)
{
foreach (MonitorInfo info in monitors)
if ((info.ActionMask & MonitorAction.Tasks) != 0)
- info.Monitor.EndTask ();
+ info.Monitor.Step (message, work);
}
-
- public void Step (int work)
+
+ protected override ProgressMonitor CreateAsyncStepMonitor ()
+ {
+ return new AggregatedProgressMonitor ();
+ }
+
+ protected override void OnBeginAsyncStep (string message, int work, ProgressMonitor stepMonitor)
{
+ var am = (AggregatedProgressMonitor) stepMonitor;
foreach (MonitorInfo info in monitors)
if ((info.ActionMask & MonitorAction.Tasks) != 0)
- info.Monitor.Step (work);
+ am.AddSlaveMonitor (info.Monitor.BeginAsyncStep (message, work));
}
-
- public TextWriter Log
+
+ protected override void OnWriteLog (string message)
{
- get { return logger; }
+ foreach (MonitorInfo info in monitors)
+ if ((info.ActionMask & MonitorAction.WriteLog) != 0)
+ info.Monitor.Log.Write (message);
}
-
- void OnWriteLog (string text)
+
+ protected override void OnWriteErrorLog (string message)
{
foreach (MonitorInfo info in monitors)
if ((info.ActionMask & MonitorAction.WriteLog) != 0)
- info.Monitor.Log.Write (text);
+ info.Monitor.ErrorLog.Write (message);
}
-
- public void ReportSuccess (string message)
+
+ protected override void OnSuccessReported (string message)
{
foreach (MonitorInfo info in monitors)
if ((info.ActionMask & MonitorAction.ReportSuccess) != 0)
info.Monitor.ReportSuccess (message);
}
-
- public void ReportWarning (string message)
+
+ protected override void OnWarningReported (string message)
{
foreach (MonitorInfo info in monitors)
if ((info.ActionMask & MonitorAction.ReportWarning) != 0)
info.Monitor.ReportWarning (message);
}
-
- public void ReportError (string message, Exception ex)
+
+ protected override void OnErrorReported (string message, Exception exception)
{
foreach (MonitorInfo info in monitors)
if ((info.ActionMask & MonitorAction.ReportError) != 0)
- info.Monitor.ReportError (message, ex);
+ info.Monitor.ReportError (message, exception);
}
-
- public void Dispose ()
+
+ public override void Dispose ()
{
foreach (MonitorInfo info in monitors) {
if ((info.ActionMask & MonitorAction.Dispose) != 0)
info.Monitor.Dispose ();
if ((info.ActionMask & MonitorAction.SlaveCancel) != 0)
- info.Monitor.CancelRequested -= new MonitorHandler (OnSlaveCancelRequested);
- }
- }
-
- public bool IsCancelRequested
- {
- get {
- foreach (MonitorInfo info in monitors)
- if ((info.ActionMask & MonitorAction.SlaveCancel) != 0) {
- if (info.Monitor.IsCancelRequested) return true;
- }
- return false;
+ info.CancellationTokenRegistration.Dispose ();
}
}
-
- public object SyncRoot {
- get { return this; }
- }
-
- void OnSlaveCancelRequested (IProgressMonitor sender)
- {
- AsyncOperation.Cancel ();
- }
-
- public IAsyncOperation AsyncOperation
- {
- get { return this; }
- }
-
- void IAsyncOperation.Cancel ()
- {
- foreach (MonitorInfo info in monitors)
- if ((info.ActionMask & MonitorAction.Cancel) != 0 && !info.Monitor.IsCancelRequested)
- info.Monitor.AsyncOperation.Cancel ();
- }
-
- void IAsyncOperation.WaitForCompleted ()
+
+ void OnSlaveCancelRequested ()
{
- masterMonitor.AsyncOperation.WaitForCompleted ();
- }
-
- public bool IsCompleted {
- get { return masterMonitor.AsyncOperation.IsCompleted; }
- }
-
- bool IAsyncOperation.Success {
- get { return masterMonitor.AsyncOperation.Success; }
- }
-
- bool IAsyncOperation.SuccessWithWarnings {
- get { return masterMonitor.AsyncOperation.SuccessWithWarnings; }
- }
-
- public event MonitorHandler CancelRequested {
- add { masterMonitor.CancelRequested += value; }
- remove { masterMonitor.CancelRequested -= value; }
- }
-
- public event OperationHandler Completed {
- add { masterMonitor.AsyncOperation.Completed += value; }
- remove { masterMonitor.AsyncOperation.Completed -= value; }
+ cancelSource.Cancel ();
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AsyncOperation.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AsyncOperation.cs
deleted file mode 100644
index 59201ae555..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/AsyncOperation.cs
+++ /dev/null
@@ -1,134 +0,0 @@
-// AsyncOperation.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-//
-
-using System;
-using System.Threading;
-
-namespace MonoDevelop.Core
-{
- public class AsyncOperation: IAsyncOperation
- {
- bool canceled;
- bool completed;
- bool success;
- bool successWithWarnings;
- IAsyncOperation trackedOperation;
- object lck = new object ();
-
- OperationHandler completedEvent;
-
- public event OperationHandler Completed {
- add {
- bool done = false;
- lock (lck) {
- if (completed)
- done = true;
- else
- completedEvent += value;
- }
- if (done)
- value (this);
- }
- remove {
- lock (lck) {
- completedEvent -= value;
- }
- }
- }
-
- public event OperationHandler CancelRequested;
-
- public bool Canceled {
- get { return canceled; }
- }
-
- public void Cancel ()
- {
- canceled = true;
- if (trackedOperation != null)
- trackedOperation.Cancel ();
- if (CancelRequested != null)
- CancelRequested (this);
- }
-
- void IAsyncOperation.WaitForCompleted ()
- {
- lock (lck) {
- if (!completed)
- Monitor.Wait (lck);
- }
- }
-
- public bool IsCompleted {
- get {
- return completed;
- }
- }
-
- public bool Success {
- get {
- return success;
- }
- }
-
- public bool SuccessWithWarnings {
- get {
- return successWithWarnings;
- }
- }
-
- public void TrackOperation (IAsyncOperation oper, bool isFinal)
- {
- if (trackedOperation != null)
- throw new InvalidOperationException ("An operation is already being tracked.");
- trackedOperation = oper;
- oper.Completed += delegate {
- if (!oper.Success || isFinal)
- SetCompleted (oper.Success, oper.SuccessWithWarnings);
- trackedOperation = null;
- };
- }
-
- public void SetCompleted (bool success)
- {
- SetCompleted (success, false);
- }
-
- public void SetCompleted (bool success, bool hasWarnings)
- {
- lock (lck) {
- completed = true;
- this.success = success;
- if (success && hasWarnings)
- successWithWarnings = true;
- Monitor.PulseAll (lck);
- if (completedEvent != null)
- completedEvent (this);
- }
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProgressMonitor.cs
index 82410eae20..fb8fc26d40 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProgressMonitor.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProgressMonitor.cs
@@ -31,7 +31,7 @@ using System.IO;
namespace MonoDevelop.Core.ProgressMonitoring
{
- public class ConsoleProgressMonitor: NullProgressMonitor
+ public class ConsoleProgressMonitor: ProgressMonitor
{
int columns = 0;
bool leaveOpen;
@@ -40,7 +40,6 @@ namespace MonoDevelop.Core.ProgressMonitoring
int ilevel = 0;
int isize = 3;
int col = -1;
- LogTextWriter logger;
bool ignoreLogMessages;
TextWriter writer;
@@ -67,8 +66,6 @@ namespace MonoDevelop.Core.ProgressMonitoring
{
this.writer = writer;
this.leaveOpen = leaveOpen;
- logger = new LogTextWriter ();
- logger.TextWritten += WriteLog;
}
public ConsoleProgressMonitor (TextWriter writer) : this (writer, false)
@@ -77,9 +74,6 @@ namespace MonoDevelop.Core.ProgressMonitoring
public override void Dispose ()
{
- logger.TextWritten -= WriteLog;
- logger.Dispose ();
-
if (!leaveOpen)
writer.Dispose ();
@@ -110,7 +104,7 @@ namespace MonoDevelop.Core.ProgressMonitoring
set { indent = value; }
}
- public override void BeginTask (string name, int totalWork)
+ protected override void OnBeginTask (string name, int totalWork, int stepWork)
{
if (!ignoreLogMessages) {
WriteText (name);
@@ -118,38 +112,29 @@ namespace MonoDevelop.Core.ProgressMonitoring
}
}
- public override void BeginStepTask (string name, int totalWork, int stepSize)
- {
- BeginTask (name, totalWork);
- }
-
- public override void EndTask ()
+ protected override void OnEndTask (string name, int totalWork, int stepWork)
{
if (!ignoreLogMessages)
Unindent ();
}
-
- void WriteLog (string text)
+
+ protected override void OnWriteLog (string message)
{
if (!ignoreLogMessages)
- WriteText (text);
- }
-
- public override TextWriter Log {
- get { return logger; }
+ WriteText (message);
}
-
- public override void ReportSuccess (string message)
+
+ protected override void OnSuccessReported (string message)
{
WriteText (message + "\n");
}
-
- public override void ReportWarning (string message)
+
+ protected override void OnWarningReported (string message)
{
WriteText ("WARNING: " + message + "\n");
}
-
- public override void ReportError (string message, Exception ex)
+
+ protected override void OnErrorReported (string message, Exception ex)
{
if (message == null && ex != null)
message = ex.Message;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProjectLoadProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProjectLoadProgressMonitor.cs
index 2447804b9b..22e3dce120 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProjectLoadProgressMonitor.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ConsoleProjectLoadProgressMonitor.cs
@@ -27,17 +27,14 @@ using System;
namespace MonoDevelop.Core.ProgressMonitoring
{
- public class ConsoleProjectLoadProgressMonitor : WrappedProgressMonitor, IProjectLoadProgressMonitor
+ public class ConsoleProjectLoadProgressMonitor : ProjectLoadProgressMonitor
{
- public MonoDevelop.Projects.Solution CurrentSolution { get; set; }
-
- public ConsoleProjectLoadProgressMonitor (IProgressMonitor monitor)
- : base (monitor)
+ public ConsoleProjectLoadProgressMonitor (ConsoleProgressMonitor monitor)
{
-
+ AddSlaveMonitor (monitor);
}
- public MonoDevelop.Projects.Extensions.MigrationType ShouldMigrateProject ()
+ public override MonoDevelop.Projects.Extensions.MigrationType ShouldMigrateProject ()
{
Console.WriteLine ("Warning: One or more projects in this solution cannot be ");
Console.WriteLine ("compiled unless they are migrated to a newer format. Please ");
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/FilteredProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/FilteredProgressMonitor.cs
index 4c1f97df84..57fae2a68f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/FilteredProgressMonitor.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/FilteredProgressMonitor.cs
@@ -34,12 +34,12 @@ namespace MonoDevelop.Core.ProgressMonitoring
// the operation being monitorized provides.
public class FilteredProgressMonitor: AggregatedProgressMonitor
{
- public FilteredProgressMonitor (IProgressMonitor targetMonitor)
+ public FilteredProgressMonitor (ProgressMonitor targetMonitor)
: this (targetMonitor, MonitorAction.WriteLog | MonitorAction.ReportError | MonitorAction.ReportWarning | MonitorAction.ReportSuccess | MonitorAction.Cancel | MonitorAction.SlaveCancel)
{
}
- public FilteredProgressMonitor (IProgressMonitor targetMonitor, MonitorAction actionMask)
+ public FilteredProgressMonitor (ProgressMonitor targetMonitor, MonitorAction actionMask)
{
AddSlaveMonitor (targetMonitor, actionMask);
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/NullAsyncOperation.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/NullAsyncOperation.cs
deleted file mode 100644
index 4262120002..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/NullAsyncOperation.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// NullAsyncOperation.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-
-using System;
-
-namespace MonoDevelop.Core.ProgressMonitoring
-{
- public class NullAsyncOperation: IAsyncOperation
- {
- public static NullAsyncOperation Success = new NullAsyncOperation (true, false);
- public static NullAsyncOperation Failure = new NullAsyncOperation (false, false);
-
- bool success;
- bool warnings;
-
- protected NullAsyncOperation (bool success, bool warnings)
- {
- this.success = success;
- this.warnings = warnings;
- }
-
- public void Cancel ()
- {
- }
-
- public void WaitForCompleted ()
- {
- }
-
- public bool IsCompleted {
- get { return true; }
- }
-
- bool IAsyncOperation.Success {
- get { return success; }
- }
-
- bool IAsyncOperation.SuccessWithWarnings {
- get { return success && warnings; }
- }
-
- public event OperationHandler Completed {
- add { value (this); }
- remove {}
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/NullProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/NullProgressMonitor.cs
deleted file mode 100644
index d79899c4f0..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/NullProgressMonitor.cs
+++ /dev/null
@@ -1,242 +0,0 @@
-//
-// NullProgressMonitor.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.IO;
-
-namespace MonoDevelop.Core.ProgressMonitoring
-{
- public class NullProgressMonitor: IProgressMonitor, IAsyncOperation
- {
- bool done, canceled, error;
- ManualResetEvent waitEvent;
- List<ProgressError> errors;
- List<string> warnings;
- List<string> messages;
-
- public object SyncRoot {
- get { return this; }
- }
-
- public string[] Messages {
- get {
- if (messages != null)
- return messages.ToArray ();
- return new string [0];
- }
- }
-
- public string[] Warnings {
- get {
- if (warnings != null)
- return warnings.ToArray ();
- return new string [0];
- }
- }
-
- public ProgressError[] Errors {
- get {
- if (errors != null)
- return errors.ToArray ();
- return new ProgressError [0];
- }
- }
-
- public virtual void BeginTask (string name, int totalWork)
- {
- }
-
- public virtual void EndTask ()
- {
- }
-
- public virtual void BeginStepTask (string name, int totalWork, int stepSize)
- {
- }
-
- public virtual void Step (int work)
- {
- }
-
- public virtual TextWriter Log {
- get { return TextWriter.Null; }
- }
-
- public virtual void ReportSuccess (string message)
- {
- if (messages == null)
- messages = new List<string> ();
- messages.Add (message);
- }
-
- public virtual void ReportWarning (string message)
- {
- if (warnings == null)
- warnings = new List<string> ();
- warnings.Add (message);
- }
-
- public virtual void ReportError (string message, Exception ex)
- {
- if (errors == null)
- errors = new List<ProgressError> ();
-
- if (message == null && ex != null)
- message = ex.Message;
- else if (message != null && ex != null) {
- if (!message.EndsWith (".")) message += ".";
- message += " " + ex.Message;
- }
-
- errors.Add (new ProgressError (message, ex));
- error = true;
- }
-
- public bool IsCancelRequested {
- get { return canceled; }
- }
-
- public virtual void Dispose ()
- {
- lock (this) {
- if (done) return;
- done = true;
- if (waitEvent != null)
- waitEvent.Set ();
- }
- OnCompleted ();
- }
-
- public IAsyncOperation AsyncOperation
- {
- get { return this; }
- }
-
- void IAsyncOperation.Cancel ()
- {
- OnCancelRequested ();
- }
-
- void IAsyncOperation.WaitForCompleted ()
- {
- lock (this) {
- if (done) return;
- if (waitEvent == null)
- waitEvent = new ManualResetEvent (false);
- }
- waitEvent.WaitOne ();
- }
-
- bool IAsyncOperation.IsCompleted
- {
- get { return done; }
- }
-
- bool IAsyncOperation.Success {
- get { return !error && !canceled; }
- }
-
- bool IAsyncOperation.SuccessWithWarnings {
- get { return !error && warnings != null; }
- }
-
- public event OperationHandler Completed {
- add {
- bool alreadyCompleted = false;
- lock (this) {
- completedEvent += value;
- alreadyCompleted = done;
- }
- if (alreadyCompleted) value (this);
- }
- remove {
- lock (this) {
- completedEvent -= value;
- }
- }
- }
-
- public event MonitorHandler CancelRequested {
- add {
- bool alreadyCanceled = false;
- lock (this) {
- cancelRequestedEvent += value;
- alreadyCanceled = canceled;
- }
- if (alreadyCanceled) value (this);
- }
- remove {
- lock (this) {
- cancelRequestedEvent -= value;
- }
- }
- }
-
- protected virtual void OnCancelRequested ()
- {
- lock (this) {
- if (canceled) return;
- canceled = true;
- }
- if (cancelRequestedEvent != null)
- cancelRequestedEvent (this);
- }
-
- protected virtual void OnCompleted ()
- {
- if (completedEvent != null)
- completedEvent (AsyncOperation);
- }
-
- event MonitorHandler cancelRequestedEvent;
- event OperationHandler completedEvent;
- }
-
- public class ProgressError
- {
- Exception ex;
- string message;
-
- public ProgressError (string message, Exception ex)
- {
- this.ex = ex;
- this.message = message;
- }
-
- public string Message {
- get { return message; }
- }
-
- public Exception Exception {
- get { return ex; }
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ProgressStatusMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ProgressStatusMonitor.cs
index b35e4043de..6f3c772b21 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ProgressStatusMonitor.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ProgressStatusMonitor.cs
@@ -33,15 +33,16 @@ namespace MonoDevelop.Core.ProgressMonitoring
{
public class ProgressStatusMonitor: MarshalByRefObject, IProgressStatus, IDisposable
{
- IProgressMonitor monitor;
+ ProgressMonitor monitor;
int step;
int logLevel;
+ bool canceled;
- public ProgressStatusMonitor (IProgressMonitor monitor): this (monitor, 1)
+ public ProgressStatusMonitor (ProgressMonitor monitor): this (monitor, 1)
{
}
- public ProgressStatusMonitor (IProgressMonitor monitor, int logLevel)
+ public ProgressStatusMonitor (ProgressMonitor monitor, int logLevel)
{
this.logLevel = logLevel;
this.monitor = monitor;
@@ -77,7 +78,7 @@ namespace MonoDevelop.Core.ProgressMonitoring
}
public bool IsCanceled {
- get { return monitor.IsCancelRequested; }
+ get { return monitor.CancellationToken.IsCancellationRequested || canceled; }
}
public int LogLevel {
@@ -87,7 +88,7 @@ namespace MonoDevelop.Core.ProgressMonitoring
public void Cancel ()
{
- monitor.AsyncOperation.Cancel ();
+ canceled = true;
}
public void Dispose ()
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/IProjectLoadProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ProjectLoadProgressMonitor.cs
index e6511a2215..e65d489a08 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/IProjectLoadProgressMonitor.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/ProjectLoadProgressMonitor.cs
@@ -28,10 +28,10 @@ using MonoDevelop.Projects.Extensions;
namespace MonoDevelop.Core
{
- public interface IProjectLoadProgressMonitor : IProgressMonitor
+ public abstract class ProjectLoadProgressMonitor : ProgressMonitor
{
- MonoDevelop.Projects.Solution CurrentSolution { get; set; }
- MigrationType ShouldMigrateProject ();
+ public MonoDevelop.Projects.Solution CurrentSolution { get; set; }
+ public abstract MigrationType ShouldMigrateProject ();
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/SimpleProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/SimpleProgressMonitor.cs
deleted file mode 100644
index 13ff23051e..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/SimpleProgressMonitor.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// SimpleProgressMonitor.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-
-namespace MonoDevelop.Core.ProgressMonitoring
-{
- public class SimpleProgressMonitor: NullProgressMonitor
- {
- ProgressTracker tracker = new ProgressTracker ();
-
- protected ProgressTracker Tracker {
- get { return tracker; }
- }
-
- public SimpleProgressMonitor()
- {
- }
-
- public override void BeginTask (string name, int totalWork)
- {
- tracker.BeginTask (name, totalWork);
- OnProgressChanged ();
- }
-
- public override void BeginStepTask (string name, int totalWork, int stepSize)
- {
- tracker.BeginStepTask (name, totalWork, stepSize);
- OnProgressChanged ();
- }
-
- public override void EndTask ()
- {
- tracker.EndTask ();
- OnProgressChanged ();
- }
-
- public override void Step (int work)
- {
- tracker.Step (work);
- OnProgressChanged ();
- }
-
- protected override void OnCompleted ()
- {
- base.OnCompleted ();
- OnProgressChanged ();
- }
-
- protected virtual void OnProgressChanged ()
- {
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/SynchronizedProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/SynchronizedProgressMonitor.cs
deleted file mode 100644
index 083000735f..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/SynchronizedProgressMonitor.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-//
-// SynchronizedProgressMonitor.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-
-using System;
-using System.Threading;
-using System.IO;
-
-namespace MonoDevelop.Core.ProgressMonitoring
-{
- public sealed class SynchronizedProgressMonitor: IProgressMonitor
- {
- IProgressMonitor monitor;
-
- public SynchronizedProgressMonitor (IProgressMonitor monitor)
- {
- this.monitor = monitor;
- }
-
- public void BeginTask (string name, int totalWork)
- {
- lock (monitor.SyncRoot) {
- monitor.BeginTask (name, totalWork);
- }
- }
-
- public void BeginStepTask (string name, int totalWork, int stepSize)
- {
- lock (monitor.SyncRoot) {
- monitor.BeginStepTask (name, totalWork, stepSize);
- }
- }
-
- public void EndTask ()
- {
- lock (monitor.SyncRoot) {
- monitor.EndTask ();
- }
- }
-
- public void Step (int work)
- {
- lock (monitor.SyncRoot) {
- monitor.Step (work);
- }
- }
-
- public TextWriter Log {
- get { return monitor.Log; }
- }
-
- public void ReportSuccess (string message)
- {
- lock (monitor.SyncRoot) {
- monitor.ReportSuccess (message);
- }
- }
-
- public void ReportWarning (string message)
- {
- lock (monitor.SyncRoot) {
- monitor.ReportWarning (message);
- }
- }
-
- public void ReportError (string message, Exception ex)
- {
- lock (monitor.SyncRoot) {
- monitor.ReportError (message, ex);
- }
- }
-
- public bool IsCancelRequested {
- get {
- lock (monitor.SyncRoot) {
- return monitor.IsCancelRequested;
- }
- }
- }
-
- public void Dispose ()
- {
- lock (monitor.SyncRoot) {
- monitor.Dispose ();
- }
- }
-
- public IAsyncOperation AsyncOperation
- {
- get {
- lock (monitor.SyncRoot) {
- return monitor.AsyncOperation;
- }
- }
- }
-
- public event MonitorHandler CancelRequested {
- add {
- lock (monitor.SyncRoot) {
- monitor.CancelRequested += value;
- }
- }
- remove {
- lock (monitor.SyncRoot) {
- monitor.CancelRequested -= value;
- }
- }
- }
-
- public object SyncRoot {
- get { return monitor.SyncRoot; }
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/WrappedProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/WrappedProgressMonitor.cs
deleted file mode 100644
index 66b961880a..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.ProgressMonitoring/WrappedProgressMonitor.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-//
-// ProjectLoadProgressMonitor.cs
-//
-// Author:
-// Alan McGovern <alan@xamarin.com>
-//
-// Copyright 2011 Xamarin Inc.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-
-namespace MonoDevelop.Core
-{
- public class WrappedProgressMonitor : IProgressMonitor
- {
- public event MonitorHandler CancelRequested {
- add { WrappedMonitor.CancelRequested += value; }
- remove { WrappedMonitor.CancelRequested -= value; }
- }
-
- public IAsyncOperation AsyncOperation {
- get { return WrappedMonitor.AsyncOperation; }
- }
-
- public bool IsCancelRequested {
- get { return WrappedMonitor.IsCancelRequested; }
- }
-
- public System.IO.TextWriter Log {
- get { return WrappedMonitor.Log; }
- }
-
- public object SyncRoot {
- get { return WrappedMonitor.SyncRoot; }
- }
-
- IProgressMonitor WrappedMonitor {
- get; set;
- }
-
- public WrappedProgressMonitor (IProgressMonitor monitor)
- {
- WrappedMonitor = monitor;
- }
-
- public void BeginStepTask (string name, int totalWork, int stepSize)
- {
- WrappedMonitor.BeginStepTask (name, totalWork, stepSize);
- }
-
- public void BeginTask (string name, int totalWork)
- {
- WrappedMonitor.BeginTask (name, totalWork);
- }
-
- public void Dispose ()
- {
- WrappedMonitor.Dispose ();
- }
-
- public void EndTask ()
- {
- WrappedMonitor.EndTask ();
- }
-
- public void ReportError (string message, Exception exception)
- {
- WrappedMonitor.ReportError (message, exception);
- }
-
- public void ReportSuccess (string message)
- {
- WrappedMonitor.ReportSuccess (message);
- }
-
- public void ReportWarning (string message)
- {
- WrappedMonitor.ReportWarning (message);
- }
-
- public void Step (int work)
- {
- WrappedMonitor.Step (work);
- }
- }
-}
-
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/SerializationContext.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/SerializationContext.cs
index 37df92c37f..d3179c26b8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/SerializationContext.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/SerializationContext.cs
@@ -37,7 +37,7 @@ namespace MonoDevelop.Core.Serialization
string file;
IPropertyFilter propertyFilter;
DataSerializer serializer;
- IProgressMonitor monitor;
+ ProgressMonitor monitor;
char directorySeparatorChar = System.IO.Path.DirectorySeparatorChar;
HashSet<ItemProperty> forcedSerializationProps;
@@ -73,7 +73,7 @@ namespace MonoDevelop.Core.Serialization
}
}
- public IProgressMonitor ProgressMonitor {
+ public ProgressMonitor ProgressMonitor {
get {
return monitor;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml
index f91a6b60eb..abba41846d 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml
@@ -118,6 +118,23 @@
</ExtensionNode>
</ExtensionPoint>
+ <ExtensionPoint path = "/MonoDevelop/ProjectModel/ProjectModelExtensions" name = "Project model extensions">
+ <Description>Project model extensions</Description>
+ <ExtensionNode name="ObjectExtension" type="MonoDevelop.Projects.Extensions.ProjectModelExtensionNode">
+ <Description>A subclass of WorkspaceObjectmExtension.</Description>
+ </ExtensionNode>
+ <ExtensionNode name="ProjectFlavor" type="MonoDevelop.Projects.Extensions.SolutionItemExtensionNode">
+ <Description>A subclass of ProjectExtension.</Description>
+ </ExtensionNode>
+ </ExtensionPoint>
+
+ <ExtensionPoint path = "/MonoDevelop/ProjectModel/MSBuildProjectExtensions" name = "MSBuild project extensions">
+ <Description>MSBuild project extensions. Specified classes must be a subclass of MSBuildProjectExtension</Description>
+ <ExtensionNode name="Class">
+ <Description>A subclass of MSBuildProjectExtension.</Description>
+ </ExtensionNode>
+ </ExtensionPoint>
+
<ExtensionPoint path = "/MonoDevelop/ProjectModel/LanguageBindings" name = "Language bindings">
<Description>Language bindings.</Description>
<ExtensionNode name="LanguageBinding" type="MonoDevelop.Projects.Extensions.LanguageBindingCodon"/>
@@ -125,9 +142,9 @@
<ExtensionPoint path = "/MonoDevelop/ProjectModel/MSBuildItemTypes" name = "MSBuild item types">
<Description>Item types supported by MSBuild</Description>
- <ExtensionNode name="SolutionItem" type="MonoDevelop.Projects.Extensions.SolutionItemNode"/>
- <ExtensionNode name="DotNetProject" type="MonoDevelop.Projects.Extensions.DotNetProjectNode"/>
- <ExtensionNode name="DotNetProjectSubtype" type="MonoDevelop.Projects.Extensions.DotNetProjectSubtypeNode"/>
+ <ExtensionNode name="SolutionItemType" type="MonoDevelop.Projects.Extensions.SolutionItemTypeNode"/>
+ <ExtensionNode name="ProjectType" type="MonoDevelop.Projects.Extensions.ProjectTypeNode"/>
+ <ExtensionNode name="DotNetProjectType" type="MonoDevelop.Projects.Extensions.DotNetProjectTypeNode"/>
</ExtensionPoint>
<ExtensionPoint path = "/MonoDevelop/ProjectModel/PolicyTypes" name = "Policy types">
@@ -149,10 +166,6 @@
<ExtensionNode objectType="MonoDevelop.Projects.Formats.MSBuild.IMSBuildGlobalPropertyProvider"/>
</ExtensionPoint>
- <ExtensionPoint path = "/MonoDevelop/ProjectModel/MSBuildExtensions" name = "MSBuild Extensions">
- <ExtensionNode name="Class" objectType="MonoDevelop.Projects.Formats.MSBuild.MSBuildExtension"/>
- </ExtensionPoint>
-
<ExtensionPoint path = "/MonoDevelop/ProjectModel/MonoDocSources" name = "MonoDoc Sources">
<ExtensionNode name="Source" type="MonoDevelop.Projects.Extensions.MonoDocSourceNode" />
</ExtensionPoint>
@@ -222,7 +235,6 @@
<Extension path = "/MonoDevelop/ProjectModel/ProjectBindings">
<ProjectBinding id = "DotNet" class = "MonoDevelop.Projects.DotNetProjectBinding" />
<ProjectBinding id = "GenericProject" class = "MonoDevelop.Projects.GenericProjectBinding" />
- <ProjectBinding id = "PortableDotNet" class = "MonoDevelop.Projects.PortableDotNetProjectBinding" />
<ProjectBinding id = "SharedAssetsProject" class = "MonoDevelop.Projects.SharedAssetsProjects.SharedAssetsProjectBinding" />
</Extension>
@@ -275,17 +287,16 @@
</Extension>
<Extension path = "/MonoDevelop/ProjectModel/MSBuildItemTypes">
- <SolutionItem guid = "{8BC9CEB9-8B4A-11D0-8D11-00A0C91BC942}"
+ <MSBuildProject guid = "{8BC9CEB9-8B4A-11D0-8D11-00A0C91BC942}"
type = "MonoDevelop.Projects.CompiledAssemblyProject"
handlerType = "MonoDevelop.Projects.Formats.MSBuild.CompiledAssemblyProjectMSBuildHandler" />
- <SolutionItem guid = "{D954291E-2A0B-460D-934E-DC6B0785DB48}"
+ <MSBuildProject guid = "{D954291E-2A0B-460D-934E-DC6B0785DB48}"
type = "MonoDevelop.Projects.SharedAssetsProjects.SharedAssetsProject"
- extension = "shproj"
- handlerType = "MonoDevelop.Projects.SharedAssetsProjects.SharedAssetsProjectMSBuildHandler" />
+ extension = "shproj" />
</Extension>
- <Extension path = "/MonoDevelop/ProjectModel/MSBuildExtensions">
- <Class class="MonoDevelop.Projects.SharedAssetsProjects.SharedAssetsProjectMSBuildExtension"/>
+ <Extension path = "/MonoDevelop/ProjectModel/ProjectModelExtensions">
+ <ProjectExtension class="MonoDevelop.Projects.SharedAssetsProjects.SharedAssetsProjectMSBuildExtension"/>
</Extension>
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
index 9d41f0a38d..54929d364b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
@@ -70,9 +70,6 @@
<NoWarn>1591;1573</NoWarn>
<DocumentationFile>..\..\..\build\bin\MonoDevelop.Core.xml</DocumentationFile>
</PropertyGroup>
- <PropertyGroup Condition="'$(BUILD_REVISION)' != ''">
- <DefineConstants>$(DefineConstants);ENABLE_RAYGUN</DefineConstants>
- </PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="Mono.Posix" />
@@ -88,6 +85,7 @@
<Reference Include="System.Web" />
<Reference Include="System.ServiceModel" />
<Reference Include="Microsoft.CSharp" />
+ <Reference Include="Microsoft.Build.Engine" />
</ItemGroup>
<ItemGroup>
<Compile Include="MonoDevelop.Core\StringParserService.cs" />
@@ -104,21 +102,16 @@
<Compile Include="MonoDevelop.Core.Execution\RemoteProcessObject.cs" />
<Compile Include="MonoDevelop.Core.ProgressMonitoring\AggregatedProgressMonitor.cs" />
<Compile Include="MonoDevelop.Core.ProgressMonitoring\ConsoleProgressMonitor.cs" />
- <Compile Include="MonoDevelop.Core\IAsyncOperation.cs" />
<Compile Include="MonoDevelop.Core\IProgressMonitor.cs" />
<Compile Include="MonoDevelop.Core.ProgressMonitoring\LogTextWriter.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\NullAsyncOperation.cs" />
<Compile Include="MonoDevelop.Core.ProgressMonitoring\ProgressTracker.cs" />
<Compile Include="MonoDevelop.Core.Execution\DefaultExecutionHandler.cs" />
<Compile Include="MonoDevelop.Core.Execution\ExternalConsoleFactory.cs" />
<Compile Include="MonoDevelop.Core.Execution\IConsole.cs" />
<Compile Include="MonoDevelop.Core.Execution\IConsoleFactory.cs" />
<Compile Include="MonoDevelop.Core.Execution\IExecutionHandler.cs" />
- <Compile Include="MonoDevelop.Core.Execution\IProcessAsyncOperation.cs" />
<Compile Include="MonoDevelop.Core.Execution\MonoPlatformExecutionHandler.cs" />
<Compile Include="MonoDevelop.Core.Execution\NativePlatformExecutionHandler.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\AggregatedOperationMonitor.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\SynchronizedProgressMonitor.cs" />
<Compile Include="MonoDevelop.Core\ClrVersion.cs" />
<Compile Include="MonoDevelop.Core\FileService.cs" />
<Compile Include="MonoDevelop.Core\FileEventArgs.cs" />
@@ -178,7 +171,6 @@
<Compile Include="MonoDevelop.Core.Collections\Set.cs" />
<Compile Include="MonoDevelop.Core.Collections\ReadOnlyDictionary.cs" />
<Compile Include="MonoDevelop.Core\Gettext.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\AsyncOperation.cs" />
<Compile Include="MonoDevelop.Core.AddIns\PackageInstalledCondition.cs" />
<Compile Include="MonoDevelop.Core\ComponentModelLocalization.cs" />
<Compile Include="MonoDevelop.Core.AddIns\ITargetRuntimeFactory.cs" />
@@ -224,12 +216,9 @@
<Compile Include="MonoDevelop.Core.Logging\RemoteLogger.cs" />
<Compile Include="MonoDevelop.Core.Instrumentation\TimeCounter.cs" />
<Compile Include="MonoDevelop.Core.AddIns\PlatformCondition.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\AggregatedAsyncOperation.cs" />
<Compile Include="MonoDevelop.Core.Serialization\BinaryDataSerializer.cs" />
<Compile Include="MonoDevelop.Core.Execution\LocalConsole.cs" />
<Compile Include="MonoDevelop.Core\IconId.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\NullProgressMonitor.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\SimpleProgressMonitor.cs" />
<Compile Include="Mono.Options.cs" />
<Compile Include="MonoDevelop.Core.Logging\InstrumentationLogger.cs" />
<Compile Include="MonoDevelop.Core.Instrumentation\TimerCounter.cs" />
@@ -237,12 +226,10 @@
<Compile Include="MonoDevelop.Projects\ProjectService.cs" />
<Compile Include="MonoDevelop.Projects\ProjectPathItemPropertyAttribute.cs" />
<Compile Include="MonoDevelop.Projects\SolutionConfiguration.cs" />
- <Compile Include="MonoDevelop.Projects\SolutionEntityItem.cs" />
<Compile Include="MonoDevelop.Projects\SolutionItemEventArgs.cs" />
<Compile Include="MonoDevelop.Projects\CombineEntryRenamedEventArgs.cs" />
<Compile Include="MonoDevelop.Projects\SolutionItemConfiguration.cs" />
<Compile Include="MonoDevelop.Projects\ProjectConfiguration.cs" />
- <Compile Include="MonoDevelop.Projects\DotNetProjectBinding.cs" />
<Compile Include="MonoDevelop.Projects\DotNetProjectConfiguration.cs" />
<Compile Include="MonoDevelop.Projects\Project.cs" />
<Compile Include="MonoDevelop.Projects\ProjectFile.cs" />
@@ -252,7 +239,6 @@
<Compile Include="MonoDevelop.Projects\ProjectFileCollection.cs" />
<Compile Include="MonoDevelop.Projects\ProjectReferenceCollection.cs" />
<Compile Include="MonoDevelop.Projects\ProjectCreateInformation.cs" />
- <Compile Include="MonoDevelop.Projects\IProjectBinding.cs" />
<Compile Include="MonoDevelop.Projects\IDotNetLanguageBinding.cs" />
<Compile Include="MonoDevelop.Projects\SolutionItemConfigurationCollection.cs" />
<Compile Include="MonoDevelop.Projects\ConfigurationEventHandler.cs" />
@@ -264,8 +250,6 @@
<Compile Include="MonoDevelop.Projects\CustomCommand.cs" />
<Compile Include="MonoDevelop.Projects\CustomCommandType.cs" />
<Compile Include="MonoDevelop.Projects\GenericProject.cs" />
- <Compile Include="MonoDevelop.Projects\GenericProjectBinding.cs" />
- <Compile Include="MonoDevelop.Projects\CustomCommandExtension.cs" />
<Compile Include="MonoDevelop.Projects\ProjectConvertTool.cs" />
<Compile Include="MonoDevelop.Projects\ProjectsServices.cs" />
<Compile Include="MonoDevelop.Projects\UnknownSolutionItem.cs" />
@@ -279,13 +263,11 @@
<Compile Include="MonoDevelop.Projects\WorkspaceItemCollection.cs" />
<Compile Include="MonoDevelop.Projects\WorkspaceItemEventArgs.cs" />
<Compile Include="MonoDevelop.Projects\SolutionEventArgs.cs" />
- <Compile Include="MonoDevelop.Projects\IWorkspaceObject.cs" />
<Compile Include="MonoDevelop.Projects\SolutionConfigurationCollection.cs" />
<Compile Include="MonoDevelop.Projects\ItemConfiguration.cs" />
<Compile Include="MonoDevelop.Projects\ItemConfigurationCollection.cs" />
<Compile Include="MonoDevelop.Projects\IConfigurationTarget.cs" />
<Compile Include="MonoDevelop.Projects\ItemCollection.cs" />
- <Compile Include="MonoDevelop.Projects\SolutionItem.cs" />
<Compile Include="MonoDevelop.Projects\SolutionFolderItemCollection.cs" />
<Compile Include="MonoDevelop.Projects\SolutionItemReference.cs" />
<Compile Include="MonoDevelop.Projects\FileFormat.cs" />
@@ -297,14 +279,10 @@
<Compile Include="MonoDevelop.Projects\FileCopySet.cs" />
<Compile Include="MonoDevelop.Projects\ProjectItem.cs" />
<Compile Include="MonoDevelop.Projects\ProjectItemCollection.cs" />
- <Compile Include="MonoDevelop.Projects\SimpleProjectItem.cs" />
<Compile Include="MonoDevelop.Projects\IFolderItem.cs" />
<Compile Include="MonoDevelop.Projects\IFileItem.cs" />
<Compile Include="MonoDevelop.Projects\ProjectParameters.cs" />
- <Compile Include="MonoDevelop.Projects\ConfigurationParameters.cs" />
<Compile Include="MonoDevelop.Projects\CyclicDependencyException.cs" />
- <Compile Include="MonoDevelop.Projects\DotNetAssemblyProject.cs" />
- <Compile Include="MonoDevelop.Projects\DotNetProjectParameters.cs" />
<Compile Include="MonoDevelop.Projects\ItemConfigurationSelector.cs" />
<Compile Include="MonoDevelop.Projects\SolutionConfigurationSelector.cs" />
<Compile Include="MonoDevelop.Projects\DefaultConfigurationSelector.cs" />
@@ -315,41 +293,31 @@
<Compile Include="MonoDevelop.Projects.Extensions\ItemPropertyCodon.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\LanguageBindingCodon.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\DataTypeCodon.cs" />
- <Compile Include="MonoDevelop.Projects.Extensions\ProjectBindingCodon.cs" />
- <Compile Include="MonoDevelop.Projects.Extensions\ItemTypeNode.cs" />
- <Compile Include="MonoDevelop.Projects.Extensions\DotNetProjectNode.cs" />
- <Compile Include="MonoDevelop.Projects.Extensions\SolutionItemNode.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\SerlializationMapNode.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\IFileFormat.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\FileFormatNode.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\ProjectExtensionUtil.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\ISolutionItemHandler.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\SolutionItemHandler.cs" />
- <Compile Include="MonoDevelop.Projects.Extensions\DotNetProjectSubtypeNode.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\PolicySetNode.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\PolicyNode.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\ItemTypeCondition.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\MonoDocSourceNode.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\ProjectLanguageCondition.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\IResourceHandler.cs" />
- <Compile Include="MonoDevelop.Projects.Extensions\IPathHandler.cs" />
<Compile Include="MonoDevelop.Projects.Extensions\IAssemblyReferenceHandler.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MD1\MD1DotNetProjectHandler.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MD1\MD1FileFormat.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MD1\MD1SolutionEntityItemHandler.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MD1\MD1SolutionItemHandler.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildFileFormat.cs" />
- <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildProjectHandler.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\SlnFileFormat.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildProjectService.cs" />
- <Compile Include="MonoDevelop.Projects.Formats.MSBuild\SlnData.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildProject.cs" />
- <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildHandler.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildImportAttribute.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\RemoteProjectBuilder.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\IMSBuildImportProvider.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\MergeToProjectAttribute.cs" />
- <Compile Include="MonoDevelop.Projects.Formats.MSBuild\CompiledAssemblyProjectMSBuildHandler.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild.Conditions\ConditionAndExpression.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild.Conditions\ConditionExpression.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild.Conditions\ConditionFactorExpresion.cs" />
@@ -413,8 +381,6 @@
<Compile Include="MonoDevelop.Core\UserProfile.cs" />
<Compile Include="MonoDevelop.Core\BrandingService.cs" />
<Compile Include="MonoDevelop.Projects\CleanEventHandler.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\IProjectLoadProgressMonitor.cs" />
- <Compile Include="MonoDevelop.Core.ProgressMonitoring\WrappedProgressMonitor.cs" />
<Compile Include="MonoDevelop.Core.ProgressMonitoring\ConsoleProjectLoadProgressMonitor.cs" />
<Compile Include="MonoDevelop.Core\SystemInformation.cs" />
<Compile Include="MonoDevelop.Core\MacSystemInformation.cs" />
@@ -430,11 +396,8 @@
<Compile Include="MonoDevelop.Core\PasswordService.cs" />
<Compile Include="MonoDevelop.Core\IPasswordProvider.cs" />
<Compile Include="MonoDevelop.Projects.Utility\ByteOrderMark.cs" />
- <Compile Include="MonoDevelop.Core.Instrumentation\IInstrumentationConsumer.cs" />
- <Compile Include="MonoDevelop.Projects\PortableDotNetProject.cs" />
<Compile Include="MonoDevelop.Core.AddIns\FilePathExtensionNode.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\TargetsAvailableCondition.cs" />
- <Compile Include="MonoDevelop.Projects\PortableDotNetProjectBinding.cs" />
<Compile Include="MonoDevelop.Core.AddIns\AssemblyInstalledCondition.cs" />
<Compile Include="MonoDevelop.Core\WebCertificateService.cs" />
<Compile Include="MonoDevelop.Core\IWebCertificateProvider.cs" />
@@ -448,11 +411,8 @@
<Compile Include="MonoDevelop.Core.Logging\AssertLoggingTraceListener.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MD1\MD1ProjectService.cs" />
<Compile Include="MonoDevelop.Projects\UnknownProject.cs" />
- <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildExtension.cs" />
<Compile Include="MonoDevelop.Projects.SharedAssetsProjects\SharedAssetsProject.cs" />
<Compile Include="MonoDevelop.Projects.SharedAssetsProjects\SharedAssetsProjectMSBuildExtension.cs" />
- <Compile Include="MonoDevelop.Projects.SharedAssetsProjects\SharedAssetsProjectMSBuildHandler.cs" />
- <Compile Include="MonoDevelop.Projects.SharedAssetsProjects\SharedAssetsProjectBinding.cs" />
<Compile Include="MonoDevelop.Core\WebRequestHelper.cs" />
<Compile Include="MonoDevelop.Core.Web\IProxyAuthenticationHandler.cs" />
<Compile Include="MonoDevelop.Core.Web\CredentialStore.cs" />
@@ -473,6 +433,55 @@
<Compile Include="MonoDevelop.Projects\IDotNetFileContainer.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\IMSBuildGlobalPropertyProvider.cs" />
<Compile Include="MonoDevelop.Projects\DotNetProjectImport.cs" />
+ <Compile Include="MonoDevelop.Core.LogReporting\CrashReporter.cs" />
+ <Compile Include="MonoDevelop.Core.Instrumentation\InstrumentationConsumer.cs" />
+ <Compile Include="MonoDevelop.Projects\DotNetProjectExtension.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\MSBuildProjectExtensionNode.cs" />
+ <Compile Include="MonoDevelop.Projects\ChainedExtension.cs" />
+ <Compile Include="MonoDevelop.Projects\ExtensionChain.cs" />
+ <Compile Include="MonoDevelop.Projects\SolutionFolderItem.cs" />
+ <Compile Include="MonoDevelop.Projects\SolutionItem.cs" />
+ <Compile Include="MonoDevelop.Projects\SolutionItemExtension.cs" />
+ <Compile Include="MonoDevelop.Projects\WorkspaceItemExtension.cs" />
+ <Compile Include="MonoDevelop.Projects\SolutionExtension.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\ProjectModelExtensionNode.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\SolutionItemExtensionNode.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\FlavorTypeCondition.cs" />
+ <Compile Include="MonoDevelop.Projects\WorkspaceObject.cs" />
+ <Compile Include="MonoDevelop.Projects\WorkspaceObjectExtension.cs" />
+ <Compile Include="MonoDevelop.Projects\IProject.cs" />
+ <Compile Include="MonoDevelop.Core.Execution\ProcessAsyncOperation.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildProperty.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildPropertyGroupMerged.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildPropertyGroup.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildItem.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildItemGroup.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildEvaluationContext.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildImport.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildObject.cs" />
+ <Compile Include="MonoDevelop.Projects\IPropertySet.cs" />
+ <Compile Include="MonoDevelop.Projects\IMSBuildDataObject.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\IMSBuildPropertySet.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildPropertyGroupEvaluated.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\SlnFile.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\UnknownSolutionItemTypeException.cs" />
+ <Compile Include="MonoDevelop.Projects.Formats.MSBuild\MSBuildProjectHandler.cs" />
+ <Compile Include="MonoDevelop.Projects\DotNetCompilerParameters.cs" />
+ <Compile Include="MonoDevelop.Projects\PortableDotNetProjectFlavor.cs" />
+ <Compile Include="MonoDevelop.Projects\SolutionItemFactory.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\ProjectMigrationHandler.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\ProjectMigrationHandlerNode.cs" />
+ <Compile Include="MonoDevelop.Projects\RegisterProjectModelExtensionAttribute.cs" />
+ <Compile Include="MonoDevelop.Projects\RegisterProjectFlavorAttribute.cs" />
+ <Compile Include="MonoDevelop.Projects\RegisterSolutionItemTypeAttribute.cs" />
+ <Compile Include="MonoDevelop.Projects\RegisterDotNetProject.cs" />
+ <Compile Include="MonoDevelop.Projects\RegisterProjectAttribute.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\SolutionItemTypeNode.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\ProjectTypeNode.cs" />
+ <Compile Include="MonoDevelop.Projects.Extensions\DotNetProjectTypeNode.cs" />
+ <Compile Include="MonoDevelop.Projects\ProjectExtension.cs" />
+ <Compile Include="MonoDevelop.Core\ProgressMonitor.cs" />
+ <Compile Include="MonoDevelop.Core.ProgressMonitoring\ProjectLoadProgressMonitor.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Makefile.am" />
@@ -560,10 +569,6 @@
<Project>{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}</Project>
<Name>ICSharpCode.NRefactory.Cecil</Name>
</ProjectReference>
- <ProjectReference Include="..\..\..\external\raygun4net\Mindscape.Raygun4Net\Mindscape.Raygun4Net.csproj">
- <Project>{495E53B3-F3AF-4C4F-BAAF-865EFAA2F4A9}</Project>
- <Name>Mindscape.Raygun4Net</Name>
- </ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="MonoDevelop.Core.dll.config">
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
index b15350f37b..851b1e289c 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
@@ -27,6 +27,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Threading.Tasks;
namespace MonoDevelop.Core
{
@@ -156,6 +157,11 @@ namespace MonoDevelop.Core
return new FilePath (path);
}
+ public Task DeleteAsync ()
+ {
+ return Task.Factory.StartNew (Delete);
+ }
+
public void Delete ()
{
// Ensure that this file/directory and all children are writable
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
index 044704ec37..575e2fcead 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
@@ -566,6 +566,36 @@ namespace MonoDevelop.Core
}
}
}
+
+ /// <summary>
+ /// Renames a directory
+ /// </summary>
+ /// <param name="sourceDir">Source directory</param>
+ /// <param name="destDir">Destination directory</param>
+ /// <remarks>
+ /// It works like Directory.Move, but it supports changing the case of a directory name in case-insensitive file systems
+ /// </remarks>
+ public static void SystemDirectoryRename (string sourceDir, string destDir)
+ {
+ if (Directory.Exists (destDir) && string.Equals (Path.GetFullPath (sourceDir), Path.GetFullPath (destDir), StringComparison.CurrentCultureIgnoreCase)) {
+ // If the destination directory exists but we can't find it with the provided name casing, then it means we are just changing the case
+ var existingDir = Directory.GetDirectories (Path.GetDirectoryName (destDir), Path.GetFileName (destDir)).FirstOrDefault ();
+ if (existingDir == null || (Path.GetFileName (existingDir) == Path.GetFileName (sourceDir))) {
+ var temp = destDir + ".renaming";
+ int n = 0;
+ while (Directory.Exists (temp) || File.Exists (temp))
+ temp = destDir + ".renaming_" + (n++);
+ Directory.Move (sourceDir, temp);
+ try {
+ Directory.Move (temp, destDir);
+ } catch {
+ Directory.Move (temp, sourceDir);
+ }
+ return;
+ }
+ }
+ Directory.Move (sourceDir, destDir);
+ }
/// <summary>
/// Removes the directory if it's empty.
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Gettext.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Gettext.cs
index 8bf16f5fc7..8f0327c28e 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Gettext.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Gettext.cs
@@ -84,6 +84,8 @@ namespace MonoDevelop.Core
// MD is located at $prefix/lib/monodevelop/bin
// adding "../../.." should give us $prefix
string prefix = Path.Combine (Path.Combine (Path.Combine (location, ".."), ".."), "..");
+ if (Platform.IsMac)
+ prefix = Path.Combine (prefix, "..", "MacOS");
//normalise it
prefix = Path.GetFullPath (prefix);
//catalogue is installed to "$prefix/share/locale" by default
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/IAsyncOperation.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/IAsyncOperation.cs
deleted file mode 100644
index 214e9d7203..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/IAsyncOperation.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// IAsyncOperation.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.IO;
-
-namespace MonoDevelop.Core
-{
- public delegate void OperationHandler (IAsyncOperation op);
-
- public interface IAsyncOperation
- {
- void Cancel ();
- void WaitForCompleted ();
- bool IsCompleted { get; }
- bool Success { get; }
- bool SuccessWithWarnings { get; }
-
- event OperationHandler Completed;
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/IProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/IProgressMonitor.cs
index f8a056ab73..5e4baec441 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/IProgressMonitor.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/IProgressMonitor.cs
@@ -29,36 +29,70 @@
using System;
using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using MonoDevelop.Core.ProgressMonitoring;
namespace MonoDevelop.Core
{
- public delegate void MonitorHandler (IProgressMonitor monitor);
+ public delegate void MonitorHandler (ProgressMonitor monitor);
- public interface IProgressMonitor: IDisposable
+ public interface IProgressMonitorFactory
{
- void BeginTask (string name, int totalWork);
- void BeginStepTask (string name, int totalWork, int stepSize);
- void EndTask ();
- void Step (int work);
-
- TextWriter Log { get; }
-
- void ReportWarning (string message);
-
- void ReportSuccess (string message);
- void ReportError (string message, Exception exception);
-
- bool IsCancelRequested { get; }
- event MonitorHandler CancelRequested;
-
- // The returned IAsyncOperation object must be thread safe
- IAsyncOperation AsyncOperation { get; }
-
- object SyncRoot { get; }
+ ProgressMonitor CreateProgressMonitor ();
}
-
- public interface IProgressMonitorFactory
+
+ public class AsyncOperation
+ {
+ public static AsyncOperation CompleteOperation = new AsyncOperation (Task.FromResult(0), null);
+
+ protected AsyncOperation ()
+ {
+ Task = Task.FromResult (0);
+ }
+
+ public AsyncOperation (Task task, CancellationTokenSource cancellationTokenSource)
+ {
+ Task = task;
+ this.CancellationTokenSource = cancellationTokenSource;
+ }
+
+ public Task Task { get; protected set; }
+
+ protected CancellationTokenSource CancellationTokenSource { get; set; }
+
+ public bool IsCompleted {
+ get { return Task.IsCompleted; }
+ }
+
+ public void Cancel ()
+ {
+ if (CancellationTokenSource != null)
+ CancellationTokenSource.Cancel ();
+ }
+
+ public void WaitForCompleted ()
+ {
+ Task.Wait ();
+ }
+ }
+
+ public class AsyncOperation<T>: AsyncOperation
+ {
+ public AsyncOperation (Task<T> task, CancellationTokenSource cancellationTokenSource): base (task, cancellationTokenSource)
+ {
+ }
+
+ public new Task<T> Task {
+ get { return (Task<T>) base.Task; }
+ }
+ }
+
+ public static class ProgressMonitorExtensions
{
- IProgressMonitor CreateProgressMonitor ();
+ public static ProgressMonitor WithCancellationSource (this ProgressMonitor monitor, CancellationTokenSource cancellationTokenSource)
+ {
+ return new AggregatedProgressMonitor (monitor, cancellationTokenSource);
+ }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs
index 1bcbd46c3e..56e1db31f6 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs
@@ -32,12 +32,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Diagnostics;
-
-#if ENABLE_RAYGUN
-using System.Threading;
-using Mindscape.Raygun4Net;
-#endif
-
+using Mono.Addins;
+using MonoDevelop.Core.LogReporting;
using MonoDevelop.Core.Logging;
using Mono.Unix.Native;
@@ -49,9 +45,6 @@ namespace MonoDevelop.Core
const string ReportCrashesKey = "MonoDevelop.LogAgent.ReportCrashes";
const string ReportUsageKey = "MonoDevelop.LogAgent.ReportUsage";
-#if ENABLE_RAYGUN
- static RaygunClient raygunClient;
-#endif
static List<ILogger> loggers = new List<ILogger> ();
static RemoteLogger remoteLogger;
static DateTime timestamp;
@@ -66,6 +59,8 @@ namespace MonoDevelop.Core
// Thirdparameter shows if the exception is fatal or not
public static Func<bool?, Exception, bool, bool?> UnhandledErrorOccured;
+ static List<CrashReporter> customCrashReporters = new List<CrashReporter> ();
+
static LoggingService ()
{
var consoleLogger = new ConsoleLogger ();
@@ -102,13 +97,6 @@ namespace MonoDevelop.Core
timestamp = DateTime.Now;
-#if ENABLE_RAYGUN
- string raygunKey = BrandingService.GetString ("RaygunApiKey");
- if (raygunKey != null) {
- raygunClient = new RaygunClient (raygunKey);
- }
-#endif
-
//remove the default trace listener on .NET, it throws up horrible dialog boxes for asserts
Debug.Listeners.Clear ();
@@ -186,6 +174,18 @@ namespace MonoDevelop.Core
RestoreOutputRedirection ();
}
+ public static void RegisterCrashReporter (CrashReporter reporter)
+ {
+ lock (customCrashReporters)
+ customCrashReporters.Add (reporter);
+ }
+
+ public static void UnregisterCrashReporter (CrashReporter reporter)
+ {
+ lock (customCrashReporters)
+ customCrashReporters.Remove (reporter);
+ }
+
internal static void ReportUnhandledException (Exception ex, bool willShutDown)
{
ReportUnhandledException (ex, willShutDown, false, null);
@@ -215,22 +215,10 @@ namespace MonoDevelop.Core
if (ReportCrashes.HasValue && !ReportCrashes.Value)
return;
- var customData = new Hashtable ();
- foreach (var cd in SystemInformation.GetDescription ())
- customData[cd.Title ?? ""] = cd.Description;
-
-#if ENABLE_RAYGUN
- if (raygunClient != null) {
- ThreadPool.QueueUserWorkItem (delegate {
- try {
- raygunClient.Send (ex, tags, customData, Runtime.Version.ToString ());
- } catch {
- // If we get here then things have gone really wrong - we can't log anything or
- // attempt to report anything. Drop any exception that ends up here.
- }
- });
+ lock (customCrashReporters) {
+ foreach (var cr in customCrashReporters.Concat (AddinManager.GetExtensionObjects<CrashReporter> (true)))
+ cr.ReportCrash (ex, willShutDown, tags);
}
-#endif
//ensure we don't lose the setting
if (ReportCrashes != oldReportCrashes) {
@@ -549,5 +537,4 @@ namespace MonoDevelop.Core
#endregion
}
-
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Platform.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Platform.cs
index cbcf9f619b..c973fa6308 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Platform.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Platform.cs
@@ -35,11 +35,16 @@ namespace MonoDevelop.Core
{
public readonly static bool IsWindows;
public readonly static bool IsMac;
-
+ public readonly static bool IsLinux;
+
+ public static Version OSVersion { get; private set; }
+
static Platform ()
{
IsWindows = Path.DirectorySeparatorChar == '\\';
IsMac = !IsWindows && IsRunningOnMac ();
+ IsLinux = !IsMac && !IsWindows;
+ OSVersion = Environment.OSVersion.Version;
// needed to make sure various p/invokes work
if (Platform.IsWindows) {
@@ -83,12 +88,31 @@ namespace MonoDevelop.Core
static void InitMacFoundation ()
{
dlopen ("/System/Library/Frameworks/Foundation.framework/Foundation", 0x1);
+ OSVersion = new Version (Gestalt ("sys1"), Gestalt ("sys2"), Gestalt ("sys3"));
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetDllDirectory (string lpPathName);
+ [System.Runtime.InteropServices.DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
+ static extern int Gestalt (int selector, out int result);
+
+ //TODO: there are other gestalt selectors that return info we might want to display
+ //mac API for obtaining info about the system
+ static int Gestalt (string selector)
+ {
+ System.Diagnostics.Debug.Assert (selector != null && selector.Length == 4);
+ int cc = selector[3] | (selector[2] << 8) | (selector[1] << 16) | (selector[0] << 24);
+ int result;
+ int ret = Gestalt (cc, out result);
+ if (ret != 0) {
+ LoggingService.LogError ("Error reading gestalt for selector '{0}': {1}", selector, ret);
+ return 0;
+ }
+ return result;
+ }
+
static void InitWindowsNativeLibs ()
{
string location = null;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ProgressMonitor.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ProgressMonitor.cs
new file mode 100644
index 0000000000..66b7c8a6a9
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ProgressMonitor.cs
@@ -0,0 +1,673 @@
+//
+// ProgressMonitor.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Linq;
+using System.IO;
+using System.Threading;
+using MonoDevelop.Core.ProgressMonitoring;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Core
+{
+ public class ProgressMonitor: IDisposable
+ {
+ ProgressTask currentTask;
+ ProgressTask parentRootTask;
+ ProgressTask rootTask;
+
+ LogTextWriter logWriter;
+ LogTextWriter errorLogWriter;
+ TextWriter customLogWriter;
+ TextWriter customErrorLogWriter;
+
+ int openStepWork = -1;
+ ProgressMonitor parentMonitor;
+ SynchronizationContext context;
+
+ List<ProgressError> errors = new List<ProgressError> ();
+ List<string> warnings = new List<string> ();
+ List<string> messages = new List<string> ();
+
+ List<ProgressMonitor> slaveMonitors;
+
+ public ProgressMonitor (): this (null, null)
+ {
+ }
+
+ public ProgressMonitor (SynchronizationContext context): this (context, null)
+ {
+ }
+
+ public ProgressMonitor (CancellationTokenSource cancellationTokenSource): this (null, cancellationTokenSource)
+ {
+ }
+
+ public ProgressMonitor (SynchronizationContext context, CancellationTokenSource cancellationTokenSource)
+ {
+ this.cancellationTokenSource = cancellationTokenSource;
+ this.context = context;
+ logWriter = new LogTextWriter ();
+ logWriter.TextWritten += OnWriteLog;
+
+ errorLogWriter = new LogTextWriter ();
+ errorLogWriter.TextWritten += OnWriteErrorLog;
+ }
+
+ void SetParentTask (ProgressMonitor parent, ProgressTask task, int work)
+ {
+ parentMonitor = parent;
+ currentTask = parentRootTask = task;
+ openStepWork = work;
+ }
+
+ public virtual void Dispose ()
+ {
+ var t = parentRootTask;
+ parentRootTask = null;
+ while (currentTask != t && currentTask != null)
+ EndTask ();
+
+ if (context != null)
+ context.Post ((o) => OnCompleted (), null);
+ else
+ OnCompleted ();
+
+ if (slaveMonitors != null) {
+ foreach (var m in slaveMonitors)
+ m.Dispose ();
+ }
+ }
+
+ protected void AddSlaveMonitor (ProgressMonitor monitor)
+ {
+ if (slaveMonitors == null)
+ slaveMonitors = new List<ProgressMonitor> ();
+ slaveMonitors.Add (monitor);
+ logWriter.ChainWriter (monitor.Log);
+ errorLogWriter.ChainWriter (monitor.ErrorLog);
+ }
+
+ protected void RemoveSlaveMonitor (ProgressMonitor monitor)
+ {
+ if (slaveMonitors == null)
+ return;
+ slaveMonitors.Remove (monitor);
+ logWriter.UnchainWriter (monitor.Log);
+ errorLogWriter.UnchainWriter (monitor.ErrorLog);
+ }
+
+ public ProgressTask CurrentTask {
+ get {
+ var t = currentTask;
+ while (t != null && t.Name == null)
+ t = t.ParentTask;
+ return t;
+ }
+ }
+
+ public string CurrentTaskName {
+ get {
+ var t = CurrentTask;
+ return t != null ? t.Name ?? "" : "";
+ }
+ }
+
+ public IEnumerable<ProgressTask> GetRootTasks ()
+ {
+ var t = rootTask;
+ if (t.Name != null)
+ return new [] {t};
+ return t.GetChildrenTasks ();
+ }
+
+ public IDisposable BeginTask (string name, int totalWork)
+ {
+ var t = new ProgressTask (this, name, totalWork);
+ if (openStepWork != -1) {
+ t.StepWork = openStepWork;
+ openStepWork = -1;
+ }
+ if (currentTask == null)
+ rootTask = t;
+ else
+ currentTask.AddChild (t);
+
+ currentTask = t;
+
+ if (name != null) {
+ if (context != null)
+ context.Post ((o) => OnBeginTask (name, totalWork, t.StepWork), null);
+ else
+ OnBeginTask (name, totalWork, t.StepWork);
+ }
+
+ ReportProgressChanged ();
+
+ if (slaveMonitors != null) {
+ foreach (var m in slaveMonitors)
+ m.BeginTask (name, totalWork);
+ }
+ return t;
+ }
+
+ public void BeginTask (int totalWork)
+ {
+ BeginTask (null, totalWork);
+ }
+
+ public void EndTask ()
+ {
+ if (currentTask != null && currentTask != parentRootTask) {
+ openStepWork = -1;
+ var t = currentTask;
+ currentTask = t.ParentTask;
+ if (currentTask == null)
+ rootTask = null;
+ t.SetComplete ();
+ if (t.Name != null) {
+ if (context != null)
+ context.Post ((o) => OnEndTask (t.Name, t.TotalWork, t.StepWork), null);
+ else
+ OnEndTask (t.Name, t.TotalWork, t.StepWork);
+ }
+ } else
+ throw new InvalidOperationException ("Task not started");
+
+ ReportProgressChanged ();
+
+ if (slaveMonitors != null) {
+ foreach (var m in slaveMonitors)
+ m.EndTask ();
+ }
+ }
+
+ internal void EndTask (ProgressTask task)
+ {
+ while (currentTask != null && currentTask != task)
+ EndTask ();
+ EndTask ();
+ }
+
+ public void Step (int work = 1)
+ {
+ Step (null, work);
+ }
+
+ public void Step (string message, int work = 1)
+ {
+ if (currentTask == null)
+ throw new InvalidOperationException ("Task not started");
+ if (work < 0)
+ throw new ArgumentException ("work can't be negative");
+
+ ConsumePendingWork ();
+ currentTask.Step (message, work);
+
+ if (context != null)
+ context.Post ((o) => {
+ OnStep (message, work);
+ ReportProgressChanged ();
+ }, null);
+ else {
+ OnStep (message, work);
+ ReportProgressChanged ();
+ }
+
+ if (slaveMonitors != null) {
+ foreach (var m in slaveMonitors)
+ m.Step (message, work);
+ }
+ }
+
+ public void BeginStep (int work = 1)
+ {
+ BeginStep (null, work);
+ }
+
+ public void BeginStep (string message, int work = 1)
+ {
+ if (currentTask == null)
+ throw new InvalidOperationException ("Task not started in progress monitor");
+ if (work < 0)
+ throw new ArgumentException ("work can't be negative");
+
+ ConsumePendingWork ();
+
+ openStepWork = work;
+ if (message != null)
+ currentTask.Step (message, 0);
+
+ ReportProgressChanged ();
+
+ if (slaveMonitors != null) {
+ foreach (var m in slaveMonitors)
+ m.BeginStep (message, work);
+ }
+ }
+
+ public void EndStep ()
+ {
+ ConsumePendingWork ();
+
+ if (slaveMonitors != null) {
+ foreach (var m in slaveMonitors)
+ m.EndStep ();
+ }
+ }
+
+ void ConsumePendingWork ()
+ {
+ if (openStepWork != -1) {
+ currentTask.Step (null, openStepWork);
+ openStepWork = -1;
+ }
+ }
+
+ public ProgressMonitor BeginAsyncStep (int work)
+ {
+ return BeginAsyncStep (null, work);
+ }
+
+ public ProgressMonitor BeginAsyncStep (string message, int work)
+ {
+ if (currentTask == null)
+ throw new InvalidOperationException ("Task not started in progress monitor");
+ if (work < 0)
+ throw new ArgumentException ("work can't be negative");
+
+ ConsumePendingWork ();
+ if (message != null)
+ currentTask.Step (message, 0);
+
+ ProgressMonitor m = null;
+ if (context != null)
+ context.Send ((o) => m = CreateAsyncStepMonitor (), null);
+ else
+ m = CreateAsyncStepMonitor ();
+
+ m.SetParentTask (this, currentTask, work);
+
+ if (context != null) {
+ context.Post ((o) => {
+ OnBeginAsyncStep (message, work, m);
+ ReportProgressChanged ();
+ }, null);
+ } else {
+ OnBeginAsyncStep (message, work, m);
+ ReportProgressChanged ();
+ }
+
+ if (slaveMonitors != null) {
+ foreach (var sm in slaveMonitors)
+ m.AddSlaveMonitor (sm.BeginAsyncStep (message, work));
+ }
+ return m;
+ }
+
+ public void ReportWarning (string message)
+ {
+ if (parentMonitor != null)
+ parentMonitor.ReportWarning (message);
+ lock (warnings)
+ warnings.Add (message);
+
+ if (context != null)
+ context.Post ((o) => OnWarningReported (message), null);
+ else
+ OnWarningReported (message);
+
+ if (slaveMonitors != null) {
+ foreach (var sm in slaveMonitors)
+ sm.ReportWarning (message);
+ }
+ }
+
+ public void ReportSuccess (string message)
+ {
+ if (parentMonitor != null)
+ parentMonitor.ReportSuccess (message);
+ lock (messages)
+ messages.Add (message);
+
+ if (context != null)
+ context.Post ((o) => OnSuccessReported (message), null);
+ else
+ OnSuccessReported (message);
+
+ if (slaveMonitors != null) {
+ foreach (var sm in slaveMonitors)
+ sm.ReportSuccess (message);
+ }
+ }
+
+ public void ReportError (string message, Exception exception = null)
+ {
+ if (parentMonitor != null)
+ parentMonitor.ReportError (message, exception);
+
+ var msg = message;
+ if (message == null && exception != null)
+ msg = exception.Message;
+
+ lock (errors)
+ errors.Add (new ProgressError (msg, exception));
+
+ if (context != null)
+ context.Post ((o) => OnErrorReported (msg, exception), null);
+ else
+ OnErrorReported (msg, exception);
+
+ if (slaveMonitors != null) {
+ foreach (var sm in slaveMonitors)
+ sm.ReportError (message, exception);
+ }
+ }
+
+ public bool HasErrors {
+ get {
+ lock (errors)
+ return errors.Count > 0;
+ }
+ }
+
+ public bool HasWarnings {
+ get {
+ lock (warnings)
+ return warnings.Count > 0;
+ }
+ }
+
+ public string[] SuccessMessages {
+ get {
+ lock (messages)
+ return messages.ToArray ();
+ }
+ }
+
+ public string[] Warnings {
+ get {
+ lock (warnings)
+ return warnings.ToArray ();
+ }
+ }
+
+ public ProgressError[] Errors {
+ get {
+ lock (errors)
+ return errors.ToArray ();
+ }
+ }
+
+ public TextWriter Log {
+ get {
+ if (parentMonitor != null)
+ return parentMonitor.Log;
+ return logWriter;
+ }
+ protected set {
+ if (parentMonitor != null)
+ throw new InvalidOperationException ("Log writter can't be modified");
+ if (customLogWriter != null)
+ logWriter.UnchainWriter (customLogWriter);
+ customLogWriter = value;
+ logWriter.ChainWriter (customLogWriter);
+ }
+ }
+
+ public TextWriter ErrorLog {
+ get {
+ if (parentMonitor != null)
+ return parentMonitor.ErrorLog;
+ return errorLogWriter ?? Log;
+ }
+ protected set {
+ if (parentMonitor != null)
+ throw new InvalidOperationException ("Log writter can't be modified");
+ if (customErrorLogWriter != null)
+ errorLogWriter.UnchainWriter (customErrorLogWriter);
+ customErrorLogWriter = value;
+ errorLogWriter.ChainWriter (customErrorLogWriter);
+ }
+ }
+
+ public CancellationToken CancellationToken {
+ get {
+ if (parentMonitor != null)
+ return parentMonitor.CancellationToken;
+ else
+ return CancellationTokenSource.Token;
+ }
+ }
+
+ public double Progress {
+ get {
+ return rootTask != null ? rootTask.Progress : 0;
+ }
+ }
+
+ public bool ProgressIsUnknown {
+ get {
+ return rootTask == null;
+ }
+ }
+
+ CancellationTokenSource cancellationTokenSource;
+
+ protected CancellationTokenSource CancellationTokenSource {
+ get {
+ if (cancellationTokenSource == null)
+ cancellationTokenSource = new CancellationTokenSource ();
+ return cancellationTokenSource;
+ } set {
+ cancellationTokenSource = value;
+ }
+ }
+
+ protected virtual void OnBeginTask (string name, int totalWork, int stepWork)
+ {
+ }
+
+ protected virtual void OnEndTask (string name, int totalWork, int stepWork)
+ {
+ }
+
+ protected virtual void OnStep (string message, int work)
+ {
+ }
+
+ protected virtual void OnBeginAsyncStep (string message, int work, ProgressMonitor stepMonitor)
+ {
+ }
+
+ protected virtual ProgressMonitor CreateAsyncStepMonitor ()
+ {
+ return new ProgressMonitor ();
+ }
+
+ protected virtual void OnSuccessReported (string message)
+ {
+ }
+
+ protected virtual void OnWarningReported (string message)
+ {
+ }
+
+ protected virtual void OnErrorReported (string message, Exception exception)
+ {
+ }
+
+ protected virtual void OnWriteLog (string message)
+ {
+ }
+
+ protected virtual void OnWriteErrorLog (string message)
+ {
+ }
+
+ void ReportProgressChanged ()
+ {
+ OnProgressChanged ();
+ if (parentMonitor != null)
+ parentMonitor.ReportProgressChanged ();
+ }
+
+ protected virtual void OnProgressChanged ()
+ {
+ }
+
+ protected virtual void OnCompleted ()
+ {
+ }
+ }
+
+ public class ProgressTask: IDisposable
+ {
+ List<ProgressTask> childrenTasks = new List<ProgressTask> ();
+
+ double currentWork;
+ double completedChildrenWork;
+ ProgressMonitor monitor;
+
+ internal ProgressTask (ProgressMonitor monitor, string name, int totalWork)
+ {
+ this.monitor = monitor;
+ Name = name;
+ TotalWork = totalWork;
+ StepWork = -1;
+ }
+
+ public int StepWork { get; set; }
+
+ bool HasStepWork {
+ get { return StepWork != -1; }
+ }
+
+ public string Name { get; private set; }
+
+ public double Progress { get; private set; }
+
+ public string StatusMessage { get; internal set; }
+
+ public int TotalWork { get; private set; }
+
+ public ProgressTask ParentTask { get; private set; }
+
+ public ProgressTask[] GetChildrenTasks ()
+ {
+ List<ProgressTask> children = new List<ProgressTask> ();
+ lock (childrenTasks) {
+ foreach (var t in childrenTasks) {
+ if (t.Name == null)
+ children.AddRange (t.GetChildrenTasks ());
+ else
+ children.Add (t);
+ }
+ }
+ return children.ToArray ();
+ }
+
+ internal void AddChild (ProgressTask task)
+ {
+ task.ParentTask = this;
+ lock (childrenTasks)
+ childrenTasks.Add (task);
+ }
+
+ internal void Step (string message, double work)
+ {
+ if (message != null)
+ StatusMessage = message;
+
+ IncCurrentWork (work);
+ }
+
+ internal void SetComplete ()
+ {
+ lock (childrenTasks) {
+ currentWork = TotalWork;
+ completedChildrenWork = 0;
+ Progress = 1;
+ if (ParentTask != null)
+ ParentTask.SetChildComplete (this);
+ }
+ }
+
+ void SetChildComplete (ProgressTask child)
+ {
+ child.ParentTask = null;
+ lock (childrenTasks) {
+ if (child.HasStepWork)
+ currentWork += child.StepWork;
+ childrenTasks.Remove (child);
+ }
+ UpdateProgressFromChildren ();
+ }
+
+ void IncCurrentWork (double work)
+ {
+ lock (childrenTasks) {
+ currentWork += work;
+ Progress = Math.Min (currentWork + completedChildrenWork, (double)TotalWork) / (double)TotalWork;
+ if (ParentTask != null && HasStepWork)
+ ParentTask.UpdateProgressFromChildren ();
+ }
+ }
+
+ void UpdateProgressFromChildren ()
+ {
+ lock (childrenTasks) {
+ completedChildrenWork = childrenTasks.Where (t => t.HasStepWork).Sum (t => t.Progress * (double)t.StepWork);
+ IncCurrentWork (0);
+ }
+ }
+
+ void IDisposable.Dispose ()
+ {
+ monitor.EndTask (this);
+ }
+ }
+
+ public class ProgressError
+ {
+ Exception ex;
+ string message;
+
+ public ProgressError (string message, Exception ex)
+ {
+ this.ex = ex;
+ this.message = message;
+ }
+
+ public string Message {
+ get { return message; }
+ }
+
+ public Exception Exception {
+ get { return ex; }
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs
index 653f215e61..53429cd8a2 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs
@@ -54,6 +54,7 @@ namespace MonoDevelop.Core
static ApplicationService applicationService;
static bool initialized;
static SynchronizationContext mainSynchronizationContext;
+ static SynchronizationContext defaultSynchronizationContext;
public static void GetAddinRegistryLocation (out string configDir, out string addinsDir, out string databaseDir)
{
@@ -80,10 +81,12 @@ namespace MonoDevelop.Core
SetupInstrumentation ();
Platform.Initialize ();
+
+ defaultSynchronizationContext = new SynchronizationContext ();
// Set a default sync context
if (SynchronizationContext.Current == null)
- SynchronizationContext.SetSynchronizationContext (new SynchronizationContext ());
+ SynchronizationContext.SetSynchronizationContext (defaultSynchronizationContext);
// Hook up the SSL certificate validation codepath
ServicePointManager.ServerCertificateValidationCallback += delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
@@ -281,7 +284,7 @@ namespace MonoDevelop.Core
public static SynchronizationContext MainSynchronizationContext {
get {
- return mainSynchronizationContext ?? SynchronizationContext.Current;
+ return mainSynchronizationContext ?? defaultSynchronizationContext;
}
set {
if (mainSynchronizationContext != null && value != null)
@@ -327,10 +330,10 @@ namespace MonoDevelop.Core
internal static class Counters
{
- public static TimerCounter RuntimeInitialization = InstrumentationService.CreateTimerCounter ("Runtime initialization", "Runtime");
+ public static TimerCounter RuntimeInitialization = InstrumentationService.CreateTimerCounter ("Runtime initialization", "Runtime", id:"Core.RuntimeInitialization");
public static TimerCounter PropertyServiceInitialization = InstrumentationService.CreateTimerCounter ("Property Service initialization", "Runtime");
- public static Counter AddinsLoaded = InstrumentationService.CreateCounter ("Add-ins loaded", "Add-in Engine", true);
+ public static Counter AddinsLoaded = InstrumentationService.CreateCounter ("Add-ins loaded", "Add-in Engine", true, id:"Core.AddinsLoaded");
public static Counter ProcessesStarted = InstrumentationService.CreateCounter ("Processes started", "Process Service");
public static Counter ExternalObjects = InstrumentationService.CreateCounter ("External objects", "Process Service");
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectNode.cs
deleted file mode 100644
index 1b0759072d..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectNode.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-// MSBuildDotNetProjectExtensionNode.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-//
-
-using System;
-using Mono.Addins;
-using MonoDevelop.Core;
-using MonoDevelop.Projects.Formats.MSBuild;
-using MonoDevelop.Projects.Extensions;
-
-namespace MonoDevelop.Projects.Extensions
-{
- public class DotNetProjectNode: ItemTypeNode
- {
- [NodeAttribute (Required=true)]
- string language = null;
-
- [NodeAttribute]
- string resourceHandler = null;
-
- public override bool CanHandleItem (SolutionEntityItem item)
- {
- return (item is DotNetProject) && ((DotNetProject)item).LanguageName == language;
- }
-
- public override bool CanHandleFile (string fileName, string typeGuid)
- {
- if (base.CanHandleFile (fileName, typeGuid))
- return true;
- else if (!string.IsNullOrEmpty (typeGuid) && typeGuid.Contains (Guid))
- {
- DotNetProjectSubtypeNode node = MSBuildProjectService.GetDotNetProjectSubtype (typeGuid);
- if (node != null && node.CanHandleFile (fileName, typeGuid))
- return true;
- }
- return false;
- }
-
- public override SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName, MSBuildFileFormat expectedFormat, string itemGuid)
- {
- MSBuildProjectHandler handler = CreateHandler<MSBuildProjectHandler> (fileName, itemGuid);
- handler.SetCustomResourceHandler (GetResourceHandler ());
- return handler.Load (monitor, fileName, expectedFormat, language, null);
- }
-
- public IResourceHandler GetResourceHandler ()
- {
- if (!string.IsNullOrEmpty (resourceHandler))
- return (IResourceHandler) Addin.CreateInstance (resourceHandler, true);
- else
- return new MSBuildResourceHandler ();
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectSubtypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectSubtypeNode.cs
deleted file mode 100644
index 2da66dcfa6..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectSubtypeNode.cs
+++ /dev/null
@@ -1,214 +0,0 @@
-// DotNetProjectSubtype.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-//
-
-using System;
-using System.Linq;
-using Mono.Addins;
-using MonoDevelop.Projects.Formats.MSBuild;
-using System.Collections.Generic;
-using MonoDevelop.Core;
-
-namespace MonoDevelop.Projects.Extensions
-{
- [ExtensionNodeChild (typeof(DotNetProjectSubtypeNodeImport), "AddImport")]
- [ExtensionNodeChild (typeof(DotNetProjectSubtypeNodeImport), "RemoveImport")]
- public class DotNetProjectSubtypeNode: ExtensionNode
- {
- #pragma warning disable 649
-
- [NodeAttribute]
- string guid = null;
-
- [NodeAttribute]
- string type = null;
-
- [NodeAttribute]
- string import = null;
-
- [NodeAttribute]
- string extension = null;
-
- [NodeAttribute]
- string exclude = null;
-
- [NodeAttribute]
- bool useXBuild = false;
-
- [NodeAttribute]
- bool requireXBuild = true;
-
- [NodeAttribute]
- string migrationHandler;
-
- [NodeAttribute]
- bool migrationRequired = true;
-
- #pragma warning restore 649
-
- Type itemType;
-
- public string Import {
- get {
- return import;
- }
- }
-
- public Type Type {
- get {
- if (itemType == null) {
- itemType = Addin.GetType (type, true);
- if (!typeof(MonoDevelop.Projects.DotNetProject).IsAssignableFrom (itemType))
- throw new InvalidOperationException ("Type must be a subclass of DotNetProject");
- }
- return itemType;
- }
- }
-
- public string Extension {
- get {
- return extension;
- }
- }
-
- public string Exclude {
- get {
- return exclude;
- }
- }
-
- public string Guid {
- get { return guid; }
- }
-
- public bool UseXBuild {
- get { return useXBuild; }
- }
-
- public bool RequireXBuild {
- get { return useXBuild && requireXBuild; }
- }
-
- public bool IsMigration {
- get { return migrationHandler != null; }
- }
-
- public bool IsMigrationRequired {
- get { return migrationRequired; }
- }
-
- public IDotNetSubtypeMigrationHandler MigrationHandler {
- get { return (IDotNetSubtypeMigrationHandler) Addin.CreateInstance (migrationHandler); }
- }
-
- public bool SupportsType (string guid)
- {
- return string.Compare (this.guid, guid, true) == 0;
- }
-
- public DotNetProject CreateInstance (string language)
- {
- return (DotNetProject) Activator.CreateInstance (Type, language);
- }
-
- public virtual bool CanHandleItem (SolutionEntityItem item)
- {
- return !(IsMigration && IsMigrationRequired) && Type.IsAssignableFrom (item.GetType ());
- }
-
- public virtual bool CanHandleType (Type type)
- {
- return !(IsMigration && IsMigrationRequired) && Type.IsAssignableFrom (type);
- }
-
- public virtual bool CanHandleFile (string fileName, string typeGuid)
- {
- if (typeGuid != null && typeGuid.ToLower().Contains(guid.ToLower()))
- return true;
- if (!string.IsNullOrEmpty (extension) && System.IO.Path.GetExtension (fileName) == "." + extension)
- return true;
- return false;
- }
-
- public virtual void InitializeHandler (SolutionEntityItem item)
- {
- MSBuildProjectHandler h = (MSBuildProjectHandler) ProjectExtensionUtil.GetItemHandler (item);
- UpdateImports (item, h.TargetImports);
- h.SubtypeGuids.Add (guid);
- h.UseMSBuildEngineByDefault |= UseXBuild;
- h.RequireMSBuildEngine |= RequireXBuild;
- }
-
- public void UpdateImports (SolutionEntityItem item, List<string> imports)
- {
- DotNetProject p = (DotNetProject) item;
- if (!string.IsNullOrEmpty (import))
- imports.AddRange (import.Split (':'));
- if (!string.IsNullOrEmpty (exclude))
- exclude.Split (':').ToList ().ForEach (i => imports.Remove (i));
-
- foreach (DotNetProjectSubtypeNodeImport iob in ChildNodes) {
- if (iob.Language == p.LanguageName) {
- if (iob.IsAdd)
- imports.AddRange (iob.Projects.Split (':'));
- else
- iob.Projects.Split (':').ToList ().ForEach (i => imports.Remove (i));
- }
- }
- }
- }
-
- class DotNetProjectSubtypeNodeImport: ExtensionNode
- {
- protected override void Read (NodeElement elem)
- {
- IsAdd = elem.NodeName == "AddImport";
- base.Read (elem);
- }
-
- [NodeAttribute ("language")]
- public string Language { get; set; }
-
- [NodeAttribute ("projects")]
- public string Projects { get; set; }
-
- public bool IsAdd { get; private set; }
- }
-
- public interface IDotNetSubtypeMigrationHandler
- {
- IEnumerable<string> FilesToBackup (string filename);
- Type Migrate (IProjectLoadProgressMonitor monitor, MSBuildProject project, string fileName, string language);
- bool CanPromptForMigration { get; }
- MigrationType PromptForMigration (IProjectLoadProgressMonitor monitor, MSBuildProject project, string fileName, string language);
- }
-
- public enum MigrationType {
- Ignore,
- Migrate,
- BackupAndMigrate,
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectTypeNode.cs
index 1dc81dafca..2a75bcf347 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemNode.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/DotNetProjectTypeNode.cs
@@ -1,4 +1,4 @@
-// SolutionItemNode.cs
+// MSBuildDotNetProjectExtensionNode.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
@@ -26,32 +26,34 @@
//
using System;
-using System.IO;
-using System.Xml;
using Mono.Addins;
-using MonoDevelop.Projects.Formats.MSBuild;
using MonoDevelop.Core;
+using MonoDevelop.Projects.Formats.MSBuild;
+using MonoDevelop.Projects.Extensions;
+using System.Threading.Tasks;
+using System.Collections.Generic;
namespace MonoDevelop.Projects.Extensions
{
- public class SolutionItemNode: ItemTypeNode
+ [ExtensionNode (ExtensionAttributeType=typeof(RegisterDotNetProjectTypeAttribute))]
+ public class DotNetProjectTypeNode: ProjectTypeNode
{
[NodeAttribute (Required=true)]
- string type = null;
+ string language = null;
- public Type ItemType {
- get { return Addin.GetType (type, true); }
+ public string Language {
+ get { return language; }
}
- public override bool CanHandleItem (SolutionEntityItem item)
+ public DotNetProjectTypeNode ()
{
- return ItemType != null && ItemType.IsAssignableFrom (item.GetType ());
+ Alias = "DotNet";
}
-
- public override SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName, MSBuildFileFormat expectedFormat, string itemGuid)
+
+ public override bool CanCreateSolutionItem (string type, ProjectCreateInformation info, System.Xml.XmlElement projectOptions)
{
- MSBuildProjectHandler handler = CreateHandler<MSBuildProjectHandler> (fileName, itemGuid);
- return handler.Load (monitor, fileName, expectedFormat, null, ItemType);
+ string lang = projectOptions.GetAttribute ("language");
+ return base.CanCreateSolutionItem (type, info, projectOptions) && lang == Language;
}
}
-} \ No newline at end of file
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/IPathHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/FlavorTypeCondition.cs
index e987803100..855a09dd15 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/IPathHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/FlavorTypeCondition.cs
@@ -1,21 +1,21 @@
-//
-// ISolutionItemHandler.cs
-//
+//
+// FlavorCondition.cs
+//
// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2010 Novell, Inc (http://www.novell.com)
-//
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
-//
+//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -23,19 +23,24 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-
using System;
-using MonoDevelop.Core;
+using System.Linq;
namespace MonoDevelop.Projects.Extensions
{
- /// <summary>
- /// This interface can be implemented by a ISolutionItemHandler class to provide
- /// custom rules for encoding and decoding paths
- /// </summary>
- public interface IPathHandler
+ public class FlavorTypeCondition: ItemTypeCondition
{
- string EncodePath (string path, string oldPath);
- string DecodePath (string path);
+ Project project;
+
+ public FlavorTypeCondition (Project project)
+ {
+ this.project = project;
+ }
+
+ protected override System.Collections.Generic.IEnumerable<Type> GetObjectTypes ()
+ {
+ return project.GetFlavors ().Select (e => e.GetType ());
+ }
}
}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/IFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/IFileFormat.cs
index 6c02e7d1f2..2a24523429 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/IFileFormat.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/IFileFormat.cs
@@ -30,6 +30,7 @@
using System;
using MonoDevelop.Core;
using System.Collections.Generic;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Extensions
{
@@ -48,10 +49,10 @@ namespace MonoDevelop.Projects.Extensions
// Makes the required changes in the object to support this file format.
// It usually means setting the ISolutionItemHandler of the item.
- void ConvertToFormat (object obj);
+ Task ConvertToFormat (object obj);
- void WriteFile (FilePath file, object obj, IProgressMonitor monitor);
- object ReadFile (FilePath file, Type expectedType, IProgressMonitor monitor);
+ Task WriteFile (FilePath file, object obj, ProgressMonitor monitor);
+ Task<object> ReadFile (FilePath file, Type expectedType, ProgressMonitor monitor);
// Returns the list of files where the object is stored
List<FilePath> GetItemFiles (object obj);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ISolutionItemHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ISolutionItemHandler.cs
index 83b0603b79..636abf31a4 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ISolutionItemHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ISolutionItemHandler.cs
@@ -27,6 +27,7 @@
using System;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Extensions
{
@@ -50,7 +51,7 @@ namespace MonoDevelop.Projects.Extensions
/// <param name='configuration'>
/// Selector to be used to get the target configuration
/// </param>
- BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration);
+ Task<BuildResult> RunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration);
/// <summary>
/// Saves the solution item
@@ -58,7 +59,7 @@ namespace MonoDevelop.Projects.Extensions
/// <param name='monitor'>
/// A progress monitor
/// </param>
- void Save (IProgressMonitor monitor);
+ Task Save (ProgressMonitor monitor);
/// <summary>
/// Gets a value indicating whether the name of the solution item should be the same as the name of the file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ItemTypeCondition.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ItemTypeCondition.cs
index 48824db647..5bd95f10eb 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ItemTypeCondition.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ItemTypeCondition.cs
@@ -34,7 +34,7 @@ namespace MonoDevelop.Projects.Extensions
public class ItemTypeCondition: ConditionType
{
Type objType;
- List<string> typeNames;
+ HashSet<string> typeNames;
IDictionary<string,string> aliases;
public ItemTypeCondition ()
@@ -87,7 +87,7 @@ namespace MonoDevelop.Projects.Extensions
aliases [alias] = fullName;
}
- bool MatchesType (string type)
+ protected bool MatchesType (string type)
{
if (type.IndexOf ('.') == -1) {
string res;
@@ -106,29 +106,36 @@ namespace MonoDevelop.Projects.Extensions
// use of the condition.
if (typeNames == null) {
- typeNames = new List<string> ();
-
- typeNames.Add (objType.FullName);
- typeNames.Add (objType.AssemblyQualifiedName);
+ typeNames = new HashSet<string> ();
+
+ foreach (var t in GetObjectTypes ()) {
+ typeNames.Add (t.FullName);
+ typeNames.Add (t.AssemblyQualifiedName);
- // base class hierarchy
+ // base class hierarchy
- Type baseType = objType.BaseType;
- while (baseType != null) {
- typeNames.Add (baseType.FullName);
- typeNames.Add (baseType.AssemblyQualifiedName);
- baseType = baseType.BaseType;
- }
+ Type baseType = t.BaseType;
+ while (baseType != null) {
+ typeNames.Add (baseType.FullName);
+ typeNames.Add (baseType.AssemblyQualifiedName);
+ baseType = baseType.BaseType;
+ }
- // Implemented interfaces
+ // Implemented interfaces
- Type[] interfaces = objType.GetInterfaces();
- foreach (Type itype in interfaces) {
- typeNames.Add (itype.FullName);
- typeNames.Add (itype.AssemblyQualifiedName);
+ Type[] interfaces = t.GetInterfaces ();
+ foreach (Type itype in interfaces) {
+ typeNames.Add (itype.FullName);
+ typeNames.Add (itype.AssemblyQualifiedName);
+ }
}
}
return typeNames.Contains (type);
}
+
+ protected virtual IEnumerable<Type> GetObjectTypes ()
+ {
+ yield return objType;
+ }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/MSBuildProjectExtensionNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/MSBuildProjectExtensionNode.cs
new file mode 100644
index 0000000000..85daa23c06
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/MSBuildProjectExtensionNode.cs
@@ -0,0 +1,46 @@
+//
+// MSBuildProjectExtensionNode.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Addins;
+
+namespace MonoDevelop.Projects.Extensions
+{
+ public class MSBuildProjectExtensionNode: TypeExtensionNode
+ {
+ [NodeAttribute (Description = "GUID of the extension. The extension will be loaded if the project has this GUID in the project type GUID list. " +
+ "If not specified, the SupportsItem method will be called on the extension to determine if it is supported or not.")]
+ string guid;
+
+ public MSBuildProjectExtensionNode ()
+ {
+ }
+
+ public string Guid {
+ get { return guid; }
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectBindingCodon.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectBindingCodon.cs
deleted file mode 100644
index c0cda37f63..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectBindingCodon.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// ProjectBindingCodon.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-
-//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-
-using System;
-using System.Collections;
-using System.ComponentModel;
-
-using Mono.Addins;
-using MonoDevelop.Projects;
-
-namespace MonoDevelop.Projects.Extensions
-{
- [ExtensionNode (Description="A project binding. The specified class must implement MonoDevelop.Projects.IProjectBinding.")]
- internal class ProjectBindingCodon : TypeExtensionNode
- {
- public IProjectBinding ProjectBinding {
- get { return (IProjectBinding) base.GetInstance (); }
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectExtensionUtil.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectExtensionUtil.cs
index 6004da536e..926dcf07e8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectExtensionUtil.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectExtensionUtil.cs
@@ -30,6 +30,7 @@ using System.IO;
using System.Collections.Generic;
using System.Threading;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Extensions
{
@@ -43,28 +44,13 @@ namespace MonoDevelop.Projects.Extensions
loadControlSlot = Thread.AllocateDataSlot ();
}
- public static ISolutionItemHandler GetItemHandler (SolutionItem item)
- {
- return item.GetItemHandler ();
- }
-
- public static void InstallHandler (ISolutionItemHandler handler, SolutionItem item)
- {
- item.SetItemHandler (handler);
- }
-
- public static SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName, ItemLoadCallback callback)
+ public async static Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, string fileName, ItemLoadCallback callback)
{
using (Counters.ReadSolutionItem.BeginTiming ("Read project " + fileName)) {
- return Services.ProjectService.GetExtensionChain (null).LoadSolutionItem (monitor, fileName, callback);
+ return await Services.ProjectService.GetExtensionChain (null).LoadSolutionItem (monitor, fileName, callback);
}
}
-
- public static BuildResult Compile (IProgressMonitor monitor, SolutionEntityItem item, BuildData buildData, ItemCompileCallback callback)
- {
- return Services.ProjectService.GetExtensionChain (item).Compile (monitor, item, buildData, callback);
- }
-
+
public static void BeginLoadOperation ()
{
Interlocked.Increment (ref loading);
@@ -94,28 +80,6 @@ namespace MonoDevelop.Projects.Extensions
if (op != null)
op.Add (rc);
}
-
- public static string EncodePath (SolutionEntityItem item, string path, string oldPath)
- {
- IPathHandler ph = item.GetItemHandler () as IPathHandler;
- if (ph != null)
- return ph.EncodePath (path, oldPath);
- else {
- string basePath = Path.GetDirectoryName (item.FileName);
- return FileService.RelativeToAbsolutePath (basePath, path);
- }
- }
-
- public static string DecodePath (SolutionEntityItem item, string path)
- {
- IPathHandler ph = item.GetItemHandler () as IPathHandler;
- if (ph != null)
- return ph.DecodePath (path);
- else {
- string basePath = Path.GetDirectoryName (item.FileName);
- return FileService.AbsoluteToRelativePath (basePath, path);
- }
- }
}
class LoadOperation
@@ -141,7 +105,7 @@ namespace MonoDevelop.Projects.Extensions
- public delegate SolutionEntityItem ItemLoadCallback (IProgressMonitor monitor, string fileName);
+ public delegate Task<SolutionItem> ItemLoadCallback (ProgressMonitor monitor, string fileName);
- public delegate BuildResult ItemCompileCallback (IProgressMonitor monitor, SolutionEntityItem item, BuildData buildData);
+ public delegate BuildResult ItemCompileCallback (ProgressMonitor monitor, SolutionItem item, BuildData buildData);
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IWorkspaceObject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectMigrationHandler.cs
index 502337e651..976dc06b42 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IWorkspaceObject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectMigrationHandler.cs
@@ -1,4 +1,4 @@
-// IWorkspaceObject.cs
+// DotNetProjectSubtype.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
@@ -26,29 +26,37 @@
//
using System;
+using System.Linq;
+using Mono.Addins;
+using MonoDevelop.Projects.Formats.MSBuild;
using System.Collections.Generic;
using MonoDevelop.Core;
-using MonoDevelop.Core.Serialization;
+using System.Threading.Tasks;
-
-namespace MonoDevelop.Projects
+namespace MonoDevelop.Projects.Extensions
{
- public interface IWorkspaceObject: IExtendedDataItem, IFolderItem, IDisposable
+ public abstract class ProjectMigrationHandler
{
- string Name { get; set; }
- FilePath ItemDirectory { get; }
- new FilePath BaseDirectory { get; set; }
- void Save (IProgressMonitor monitor);
+ public virtual IEnumerable<string> FilesToBackup (string filename)
+ {
+ yield break;
+ }
+
+ public abstract bool Migrate (ProjectLoadProgressMonitor monitor, MSBuildProject project, string fileName, string language);
+
+ public virtual bool CanPromptForMigration {
+ get { return false; }
+ }
+
+ public virtual MigrationType PromptForMigration (ProjectLoadProgressMonitor monitor, MSBuildProject project, string fileName, string language)
+ {
+ throw new NotImplementedException ();
+ }
}
- public interface IWorkspaceFileObject: IWorkspaceObject, IFileItem
- {
- FileFormat FileFormat { get; }
- void ConvertToFormat (FileFormat format, bool convertChildren);
- bool SupportsFormat (FileFormat format);
- List<FilePath> GetItemFiles (bool includeReferencedFiles);
- new FilePath FileName { get; set; }
- bool NeedsReload { get; set; }
- bool ItemFilesChanged { get; }
+ public enum MigrationType {
+ Ignore,
+ Migrate,
+ BackupAndMigrate,
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectMigrationHandlerNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectMigrationHandlerNode.cs
new file mode 100644
index 0000000000..9e61188b88
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectMigrationHandlerNode.cs
@@ -0,0 +1,45 @@
+//
+// ProjectMigrationHandlerNode.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Addins;
+
+namespace MonoDevelop.Projects.Extensions
+{
+ public class ProjectMigrationHandlerNode: TypeExtensionNode
+ {
+ [NodeAttribute]
+ bool migrationRequired = true;
+
+ public bool IsMigrationRequired {
+ get { return migrationRequired; }
+ }
+
+ public ProjectMigrationHandler MigrationHandler {
+ get { return (ProjectMigrationHandler) CreateInstance (typeof(ProjectMigrationHandler)); }
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectModelExtensionNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectModelExtensionNode.cs
new file mode 100644
index 0000000000..bcd5bf6a81
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectModelExtensionNode.cs
@@ -0,0 +1,45 @@
+//
+// ProjectModelExtensionNode.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Addins;
+
+namespace MonoDevelop.Projects.Extensions
+{
+ [ExtensionNode (ExtensionAttributeType = typeof(RegisterProjectModelExtensionAttribute))]
+ public class ProjectModelExtensionNode: TypeExtensionNode
+ {
+ public virtual bool CanHandleObject (object ob)
+ {
+ return ob is WorkspaceObject;
+ }
+
+ public virtual WorkspaceObjectExtension CreateExtension ()
+ {
+ return (WorkspaceObjectExtension) CreateInstance (typeof(WorkspaceObjectExtension));
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs
new file mode 100644
index 0000000000..407a77db63
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs
@@ -0,0 +1,62 @@
+//
+// MSBuildProjectNode.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using MonoDevelop.Projects.Formats.MSBuild;
+using Mono.Addins;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.Projects.Extensions
+{
+ [ExtensionNode (ExtensionAttributeType=typeof(RegisterProjectTypeAttribute))]
+ public class ProjectTypeNode: SolutionItemTypeNode
+ {
+ public override async Task<SolutionItem> CreateSolutionItem (ProgressMonitor monitor, string fileName, string typeGuid)
+ {
+ MSBuildProject p = null;
+
+ if (!string.IsNullOrEmpty (fileName)) {
+ p = await MSBuildProject.LoadAsync (fileName);
+// if (MSBuildProjectService.CanMigrateFlavor (p.ProjectTypeGuids))
+// await MSBuildProjectService.MigrateFlavor (monitor, fileName, typeGuid, this, p);
+ }
+
+ if (p != null)
+ Project.CreationContext.LockContext (p, typeGuid);
+ try {
+ var project = await base.CreateSolutionItem (monitor, fileName, typeGuid) as Project;
+ if (project == null)
+ throw new InvalidOperationException ("Project node type is not a subclass of MonoDevelop.Projects.Project");
+ return project;
+ } finally {
+ if (p != null)
+ Project.CreationContext.UnlockContext ();
+ }
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemExtensionNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemExtensionNode.cs
new file mode 100644
index 0000000000..4b64b1f20e
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemExtensionNode.cs
@@ -0,0 +1,64 @@
+//
+// SolutionItemExtensionNode.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Addins;
+using System.Linq;
+
+namespace MonoDevelop.Projects.Extensions
+{
+ [ExtensionNode (ExtensionAttributeType = typeof(RegisterProjectFlavorAttribute))]
+ public class SolutionItemExtensionNode: ProjectModelExtensionNode
+ {
+ [NodeAttribute (Description = "GUID of the extension. The extension will be loaded if the project has this GUID in the project type GUID list. " +
+ "If not specified, the extension will be applied to all projects.")]
+ string guid;
+
+ public string Guid {
+ get { return guid; }
+ }
+
+ public override bool CanHandleObject (object ob)
+ {
+ SolutionItem p = ob as SolutionItem;
+ if (p == null)
+ return false;
+
+ if (guid == null)
+ return true;
+
+ var typeGuids = p.GetItemTypeGuids ();
+ return typeGuids.Any (g => string.Equals (g, guid, StringComparison.InvariantCultureIgnoreCase));
+ }
+
+ public override WorkspaceObjectExtension CreateExtension ()
+ {
+ var ext = (ProjectExtension) CreateInstance (typeof(ProjectExtension));
+ ext.FlavorGuid = Guid;
+ return ext;
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemHandler.cs
index 835a0c2d92..887af95949 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemHandler.cs
@@ -29,14 +29,15 @@ using System;
using System.CodeDom.Compiler;
using MonoDevelop.Core;
using MonoDevelop.Projects.Extensions;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Extensions
{
public abstract class SolutionItemHandler: ISolutionItemHandler
{
- SolutionItem item;
+ SolutionFolderItem item;
- public SolutionItemHandler (SolutionItem item)
+ public SolutionItemHandler (SolutionFolderItem item)
{
this.item = item;
}
@@ -45,30 +46,30 @@ namespace MonoDevelop.Projects.Extensions
get { return true; }
}
- public SolutionItem Item {
+ public SolutionFolderItem Item {
get { return item; }
}
- public virtual BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ public async virtual Task<BuildResult> RunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration)
{
switch (target)
{
case "Build":
- return OnBuild (monitor, configuration);
+ return await OnBuild (monitor, configuration);
case "Clean":
- return OnClean (monitor, configuration);
+ return await OnClean (monitor, configuration);
}
return new BuildResult (new CompilerResults (null), "");
}
- protected virtual BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected virtual Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
{
- return null;
+ return Task.FromResult (BuildResult.Success);
}
- protected virtual BuildResult OnClean (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected virtual Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
{
- return null;
+ return Task.FromResult (BuildResult.Success);
}
public virtual void Dispose ()
@@ -77,7 +78,7 @@ namespace MonoDevelop.Projects.Extensions
public abstract string ItemId { get; }
- public abstract void Save (IProgressMonitor monitor);
+ public abstract Task Save (ProgressMonitor monitor);
public virtual void OnModified (string hint)
{
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ItemTypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs
index 7608071bee..3b9a46a8db 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ItemTypeNode.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs
@@ -31,10 +31,13 @@ using System.Xml;
using Mono.Addins;
using MonoDevelop.Projects.Formats.MSBuild;
using MonoDevelop.Core;
+using System.Threading.Tasks;
+using MonoDevelop.Core.ProgressMonitoring;
namespace MonoDevelop.Projects.Extensions
{
- public abstract class ItemTypeNode: ExtensionNode
+ [ExtensionNode (ExtensionAttributeType=typeof(RegisterSolutionItemTypeAttribute))]
+ public abstract class SolutionItemTypeNode: ExtensionNode
{
[NodeAttribute (Required=true)]
string guid = null;
@@ -46,13 +49,16 @@ namespace MonoDevelop.Projects.Extensions
string import = null;
[NodeAttribute]
- string handlerType = null;
-
- public ItemTypeNode ()
+ string type = null;
+
+ [NodeAttribute ("alias")]
+ public string Alias { get; protected set; }
+
+ public SolutionItemTypeNode ()
{
}
- public ItemTypeNode (string guid, string extension, string import)
+ public SolutionItemTypeNode (string guid, string extension, string import)
{
this.guid = guid;
this.extension = extension;
@@ -74,14 +80,13 @@ namespace MonoDevelop.Projects.Extensions
return import;
}
}
-
- public abstract bool CanHandleItem (SolutionEntityItem item);
-
- public virtual void InitializeHandler (SolutionEntityItem item)
- {
- MSBuildHandler h = CreateHandler<MSBuildHandler> (null, null);
- h.Item = item;
- item.SetItemHandler (h);
+
+ internal string ItenTypeName {
+ get { return type; }
+ }
+
+ public virtual Type ItemType {
+ get { return Addin.GetType (type, true); }
}
public virtual bool CanHandleFile (string fileName, string typeGuid)
@@ -92,32 +97,29 @@ namespace MonoDevelop.Projects.Extensions
return true;
return false;
}
+
+ SolutionItemFactory factory;
- protected T CreateHandler<T> (string fileName, string itemGuid) where T:MSBuildHandler
+ public virtual async Task<SolutionItem> CreateSolutionItem (ProgressMonitor monitor, string fileName, string typeGuid)
{
- MSBuildHandler h = OnCreateHandler (fileName, itemGuid);
- if (!(h is T))
- throw new InvalidOperationException ("Error while creating a MSBuildHandler. Expected an object of type '" + typeof(T).FullName + ", found type '" + h.GetType ());
- return (T)h;
+ if (typeof(SolutionItemFactory).IsAssignableFrom (ItemType)) {
+ if (factory == null)
+ factory = (SolutionItemFactory) Activator.CreateInstance (ItemType);
+ return await factory.CreateItem (fileName, typeGuid);
+ }
+ return (SolutionItem) Activator.CreateInstance (ItemType);
}
-
- protected virtual MSBuildHandler OnCreateHandler (string fileName, string itemGuid)
+
+ public virtual bool CanCreateSolutionItem (string type, ProjectCreateInformation info, System.Xml.XmlElement projectOptions)
{
- MSBuildHandler h;
- if (!string.IsNullOrEmpty (handlerType)) {
- h = Addin.CreateInstance (handlerType, true) as MSBuildHandler;
- if (h == null)
- throw new InvalidOperationException ("Type '" + handlerType + "' must be a subclass of 'MonoDevelop.Projects.Formats.MSBuild.MSBuildHandler'");
- if (h is MSBuildProjectHandler)
- ((MSBuildProjectHandler)h).Initialize (Guid, Import, itemGuid);
- else
- h.Initialize (Guid, itemGuid);
- } else {
- h = new MSBuildProjectHandler (Guid, Import, itemGuid);
- }
- return h;
+ return type.Equals (Guid, StringComparison.OrdinalIgnoreCase) || type == Alias;
+ }
+
+ public virtual SolutionItem CreateSolutionItem (string type, ProjectCreateInformation info, System.Xml.XmlElement projectOptions)
+ {
+ var item = CreateSolutionItem (new ProgressMonitor (), null, Guid).Result;
+ item.InitializeNew (info, projectOptions);
+ return item;
}
-
- public abstract SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName, MSBuildFileFormat expectedFormat, string itemGuid);
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1DotNetProjectHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1DotNetProjectHandler.cs
index c370403ffa..605464cee2 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1DotNetProjectHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1DotNetProjectHandler.cs
@@ -35,6 +35,7 @@ using MonoDevelop.Core;
using MonoDevelop.Core.Execution;
using MonoDevelop.Projects.Extensions;
using Microsoft.Build.BuildEngine;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Formats.MD1
{
@@ -48,9 +49,9 @@ namespace MonoDevelop.Projects.Formats.MD1
get { return (DotNetProject) Item; }
}
- protected override BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected async override Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
{
- if (!Project.InternalCheckNeedsBuild (configuration)) {
+ if (!Project.OnGetNeedsBuilding (configuration)) {
monitor.Log.WriteLine (GettextCatalog.GetString ("Skipping project since output files are up to date"));
return new BuildResult ();
}
@@ -150,25 +151,36 @@ namespace MonoDevelop.Projects.Formats.MD1
buildData.Configuration.SetParentItem (project);
buildData.ConfigurationSelector = configuration;
- return ProjectExtensionUtil.Compile (monitor, project, buildData, delegate {
+ return await Task<BuildResult>.Factory.StartNew (delegate {
ProjectItemCollection items = buildData.Items;
- BuildResult res = BuildResources (buildData.Configuration, ref items, monitor);
- if (res != null)
- return res;
-
- res = project.LanguageBinding.Compile (items, buildData.Configuration, buildData.ConfigurationSelector, monitor);
+ BuildResult br = BuildResources (buildData.Configuration, ref items, monitor);
+ if (br != null)
+ return br;
+
+ br = project.LanguageBinding.Compile (items, buildData.Configuration, buildData.ConfigurationSelector, monitor);
if (refres != null) {
- refres.Append (res);
+ refres.Append (br);
return refres;
- }
- else
- return res;
+ } else
+ return br;
+ });
+
+ }
+
+ internal static Task<BuildResult> Compile (ProgressMonitor monitor, DotNetProject project, BuildData buildData)
+ {
+ return Task<BuildResult>.Factory.StartNew (delegate {
+ ProjectItemCollection items = buildData.Items;
+ BuildResult br = BuildResources (buildData.Configuration, ref items, monitor);
+ if (br != null)
+ return br;
+ return project.LanguageBinding.Compile (items, buildData.Configuration, buildData.ConfigurationSelector, monitor);
});
- }
+ }
// Builds the EmbedAsResource files. If any localized resources are found then builds the satellite assemblies
// and sets @projectItems to a cloned collection minus such resource files.
- private BuildResult BuildResources (DotNetProjectConfiguration configuration, ref ProjectItemCollection projectItems, IProgressMonitor monitor)
+ internal static BuildResult BuildResources (DotNetProjectConfiguration configuration, ref ProjectItemCollection projectItems, ProgressMonitor monitor)
{
string resgen = configuration.TargetRuntime.GetToolPath (configuration.TargetFramework, "resgen");
ExecutionEnvironment env = configuration.TargetRuntime.GetToolsExecutionEnvironment (configuration.TargetFramework);
@@ -220,7 +232,7 @@ namespace MonoDevelop.Projects.Formats.MD1
return null;
}
- CompilerError GetResourceId (FilePath outputFile, ExecutionEnvironment env, ProjectFile finfo, ref string fname, string resgen, out string resourceId, IProgressMonitor monitor)
+ static CompilerError GetResourceId (FilePath outputFile, ExecutionEnvironment env, ProjectFile finfo, ref string fname, string resgen, out string resourceId, ProgressMonitor monitor)
{
resourceId = finfo.ResourceId;
if (resourceId == null) {
@@ -326,7 +338,7 @@ namespace MonoDevelop.Projects.Formats.MD1
return finfo_first.LastWriteTime > finfo_second.LastWriteTime;
}
- CompilerError GenerateSatelliteAssemblies (Dictionary<string, string> resourcesByCulture, string outputDir, string al, string defaultns, IProgressMonitor monitor)
+ static CompilerError GenerateSatelliteAssemblies (Dictionary<string, string> resourcesByCulture, string outputDir, string al, string defaultns, ProgressMonitor monitor)
{
foreach (KeyValuePair<string, string> pair in resourcesByCulture) {
string culture = pair.Key;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1FileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1FileFormat.cs
index 669a0e92c7..a4ec7999ee 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1FileFormat.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1FileFormat.cs
@@ -33,6 +33,7 @@ using System.Xml;
using MonoDevelop.Core.Serialization;
using MonoDevelop.Projects.Extensions;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Formats.MD1
{
@@ -65,7 +66,7 @@ namespace MonoDevelop.Projects.Formats.MD1
return new List<FilePath> ();
}
- public void WriteFile (FilePath file, object node, IProgressMonitor monitor)
+ async public Task WriteFile (FilePath file, object node, ProgressMonitor monitor)
{
string tmpfilename = null;
try {
@@ -76,9 +77,9 @@ namespace MonoDevelop.Projects.Formats.MD1
}
if (tmpfilename == null) {
- WriteFileInternal (file, file, node, monitor);
+ await WriteFileInternal (file, file, node, monitor);
} else {
- WriteFileInternal (file, tmpfilename, node, monitor);
+ await WriteFileInternal (file, tmpfilename, node, monitor);
File.Delete (file);
File.Move (tmpfilename, file);
}
@@ -89,45 +90,47 @@ namespace MonoDevelop.Projects.Formats.MD1
}
}
- void WriteFileInternal (FilePath actualFile, FilePath outFile, object node, IProgressMonitor monitor)
+ Task WriteFileInternal (FilePath actualFile, FilePath outFile, object node, ProgressMonitor monitor)
{
- WriteWorkspaceItem (actualFile, outFile, (WorkspaceItem) node, monitor);
+ return WriteWorkspaceItem (actualFile, outFile, (WorkspaceItem) node, monitor);
}
- void WriteWorkspaceItem (FilePath actualFile, FilePath outFile, WorkspaceItem item, IProgressMonitor monitor)
+ async Task WriteWorkspaceItem (FilePath actualFile, FilePath outFile, WorkspaceItem item, ProgressMonitor monitor)
{
Workspace ws = item as Workspace;
if (ws != null) {
monitor.BeginTask (null, ws.Items.Count);
try {
foreach (WorkspaceItem it in ws.Items) {
- it.Save (monitor);
+ await it.SaveAsync (monitor);
monitor.Step (1);
}
} finally {
monitor.EndTask ();
}
}
-
- StreamWriter sw = new StreamWriter (outFile);
- try {
- monitor.BeginTask (GettextCatalog.GetString ("Saving item: {0}", actualFile), 1);
- XmlTextWriter tw = new XmlTextWriter (sw);
- tw.Formatting = Formatting.Indented;
- XmlDataSerializer ser = new XmlDataSerializer (MD1ProjectService.DataContext);
- ser.SerializationContext.BaseFile = actualFile;
- ser.SerializationContext.ProgressMonitor = monitor;
- ser.Serialize (sw, item, typeof(WorkspaceItem));
- } catch (Exception ex) {
- monitor.ReportError (GettextCatalog.GetString ("Could not save item: {0}", actualFile), ex);
- throw;
- } finally {
- monitor.EndTask ();
- sw.Close ();
- }
+
+ await Task.Factory.StartNew (delegate {
+ StreamWriter sw = new StreamWriter (outFile);
+ try {
+ monitor.BeginTask (GettextCatalog.GetString ("Saving item: {0}", actualFile), 1);
+ XmlTextWriter tw = new XmlTextWriter (sw);
+ tw.Formatting = Formatting.Indented;
+ XmlDataSerializer ser = new XmlDataSerializer (MD1ProjectService.DataContext);
+ ser.SerializationContext.BaseFile = actualFile;
+ ser.SerializationContext.ProgressMonitor = monitor;
+ ser.Serialize (sw, item, typeof(WorkspaceItem));
+ } catch (Exception ex) {
+ monitor.ReportError (GettextCatalog.GetString ("Could not save item: {0}", actualFile), ex);
+ throw;
+ } finally {
+ monitor.EndTask ();
+ sw.Close ();
+ }
+ });
}
- public object ReadFile (FilePath fileName, Type expectedType, IProgressMonitor monitor)
+ public async Task<object> ReadFile (FilePath fileName, Type expectedType, ProgressMonitor monitor)
{
string ext = Path.GetExtension (fileName).ToLower ();
if (ext != ".mdw")
@@ -137,43 +140,44 @@ namespace MonoDevelop.Projects.Formats.MD1
ProjectExtensionUtil.BeginLoadOperation ();
try {
- readObject = ReadWorkspaceItemFile (fileName, monitor);
+ readObject = await ReadWorkspaceItemFile (fileName, monitor);
} finally {
ProjectExtensionUtil.EndLoadOperation ();
}
IWorkspaceFileObject fo = readObject as IWorkspaceFileObject;
if (fo != null)
- fo.ConvertToFormat (MD1ProjectService.FileFormat, false);
+ await fo.ConvertToFormat (MD1ProjectService.FileFormat, false);
return readObject;
}
- object ReadWorkspaceItemFile (FilePath fileName, IProgressMonitor monitor)
+ Task<object> ReadWorkspaceItemFile (FilePath fileName, ProgressMonitor monitor)
{
- XmlTextReader reader = new XmlTextReader (new StreamReader (fileName));
- try {
- monitor.BeginTask (string.Format (GettextCatalog.GetString ("Loading workspace item: {0}"), fileName), 1);
- reader.MoveToContent ();
- XmlDataSerializer ser = new XmlDataSerializer (MD1ProjectService.DataContext);
- ser.SerializationContext.BaseFile = fileName;
- ser.SerializationContext.ProgressMonitor = monitor;
- WorkspaceItem entry = (WorkspaceItem) ser.Deserialize (reader, typeof(WorkspaceItem));
- entry.ConvertToFormat (MD1ProjectService.FileFormat, false);
- entry.FileName = fileName;
- return entry;
- }
- catch (Exception ex) {
- monitor.ReportError (string.Format (GettextCatalog.GetString ("Could not load solution item: {0}"), fileName), ex);
- throw;
- }
- finally {
- monitor.EndTask ();
- reader.Close ();
- }
+ return Task<object>.Factory.StartNew (delegate {
+ XmlTextReader reader = new XmlTextReader (new StreamReader (fileName));
+ try {
+ monitor.BeginTask (string.Format (GettextCatalog.GetString ("Loading workspace item: {0}"), fileName), 1);
+ reader.MoveToContent ();
+ XmlDataSerializer ser = new XmlDataSerializer (MD1ProjectService.DataContext);
+ ser.SerializationContext.BaseFile = fileName;
+ ser.SerializationContext.ProgressMonitor = monitor;
+ WorkspaceItem entry = (WorkspaceItem)ser.Deserialize (reader, typeof(WorkspaceItem));
+ entry.ConvertToFormat (MD1ProjectService.FileFormat, false).Wait ();
+ entry.FileName = fileName;
+ return entry;
+ } catch (Exception ex) {
+ monitor.ReportError (string.Format (GettextCatalog.GetString ("Could not load solution item: {0}"), fileName), ex);
+ throw;
+ } finally {
+ monitor.EndTask ();
+ reader.Close ();
+ }
+ });
}
- public void ConvertToFormat (object obj)
+ public Task ConvertToFormat (object obj)
{
+ return Task.FromResult (0);
}
public IEnumerable<string> GetCompatibilityWarnings (object obj)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionEntityItemHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionEntityItemHandler.cs
index 6034c074c4..7515e2b50a 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionEntityItemHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionEntityItemHandler.cs
@@ -29,19 +29,20 @@ using System;
using System.CodeDom.Compiler;
using MonoDevelop.Core;
using MonoDevelop.Projects.Extensions;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Formats.MD1
{
internal class MD1SolutionEntityItemHandler: MD1SolutionItemHandler
{
- public MD1SolutionEntityItemHandler (SolutionEntityItem item): base (item)
+ public MD1SolutionEntityItemHandler (SolutionItem item): base (item)
{
}
- public override void Save (IProgressMonitor monitor)
+ public override Task Save (ProgressMonitor monitor)
{
- SolutionEntityItem it = (SolutionEntityItem) Item;
- it.FileFormat.Format.WriteFile (it.FileName, it, monitor);
+ SolutionItem it = (SolutionItem) Item;
+ return it.FileFormat.Format.WriteFile (it.FileName, it, monitor);
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionItemHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionItemHandler.cs
index 4d971784bb..544f48a3de 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionItemHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1SolutionItemHandler.cs
@@ -29,16 +29,17 @@ using System;
using System.CodeDom.Compiler;
using MonoDevelop.Core;
using MonoDevelop.Projects.Extensions;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Formats.MD1
{
internal class MD1SolutionItemHandler: SolutionItemHandler
{
- public MD1SolutionItemHandler (SolutionItem item): base (item)
+ public MD1SolutionItemHandler (SolutionFolderItem item): base (item)
{
}
- public override void Save (IProgressMonitor monitor)
+ public override Task Save (ProgressMonitor monitor)
{
throw new NotSupportedException ();
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/CompiledAssemblyProjectMSBuildHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/CompiledAssemblyProjectMSBuildHandler.cs
deleted file mode 100644
index 513a286921..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/CompiledAssemblyProjectMSBuildHandler.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// CompiledAssemblyProjectMSBuildHandler.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2010 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using MonoDevelop.Core.Serialization;
-using MonoDevelop.Core;
-
-namespace MonoDevelop.Projects.Formats.MSBuild
-{
- class CompiledAssemblyProjectMSBuildHandler: MSBuildProjectHandler
- {
- public override bool HasSlnData {
- get {
- return true;
- }
- }
-
- public override DataItem WriteSlnData ()
- {
- DataSerializer ser = new DataSerializer (MSBuildProjectService.DataContext);
- ser.SerializationContext.BaseFile = EntityItem.FileName;
- ser.SerializationContext.DirectorySeparatorChar = '\\';
- DataItem data = (DataItem) ser.Serialize (EntityItem, typeof(CompiledAssemblyProject));
- return data;
- }
-
- public override void ReadSlnData (DataItem item)
- {
- // Remove the default configuration, since new ones will be loaded
- CompiledAssemblyProject project = (CompiledAssemblyProject) EntityItem;
- project.Configurations.Clear ();
-
- DataSerializer ser = new DataSerializer (MSBuildProjectService.DataContext);
- ser.SerializationContext.BaseFile = EntityItem.FileName;
- ser.SerializationContext.DirectorySeparatorChar = '\\';
- ser.Deserialize (project, item);
- }
-
- protected override void SaveItem (IProgressMonitor monitor)
- {
- // Do nothing, since info is saved to the .sln
- }
- }
-}
-
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildImportProvider.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildImportProvider.cs
index 397e432eaf..65f43a52b5 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildImportProvider.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildImportProvider.cs
@@ -31,6 +31,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild
{
public interface IMSBuildImportProvider
{
- void UpdateImports (SolutionEntityItem item, List<string> imports);
+ void UpdateImports (SolutionItem item, List<string> imports);
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildProject.cs
new file mode 100644
index 0000000000..a43393337c
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildProject.cs
@@ -0,0 +1,519 @@
+//
+// IMSBuildProject.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using MonoDevelop.Core;
+using System.Collections.Generic;
+using System.Xml;
+using System.Xml.Linq;
+using System.Linq;
+
+namespace MonoDevelop.Projects.Formats.MSBuildInternal
+{
+ public abstract class MSBuildProject
+ {
+ Dictionary<object,Dictionary<Type,IMSBuildDataObject>> customDataObjects = new Dictionary<object,Dictionary<Type,IMSBuildDataObject>> ();
+ Dictionary<string, MSBuildItemGroup> bestGroups;
+
+ public abstract FilePath FileName { get; }
+
+ public FilePath BaseDirectory {
+ get { return FileName.ParentDirectory; }
+ }
+
+ public abstract void Load (FilePath file);
+
+ public abstract void Save (string fileName);
+
+ public abstract string SaveToString ();
+
+ public MonoDevelop.Projects.Formats.MSBuild.MSBuildFileFormat Format {
+ get;
+ set;
+ }
+
+ public abstract string DefaultTargets { get; set; }
+
+ public abstract string ToolsVersion { get; set; }
+
+ public T GetObject<T> () where T : IMSBuildDataObject, new()
+ {
+ return GetObject<T> (this);
+ }
+
+ public void SetObject<T> (T t) where T : IMSBuildDataObject
+ {
+ SetObject<T> (this, t);
+ }
+
+ internal T GetObject<T> (object owner) where T : IMSBuildDataObject, new()
+ {
+ Dictionary<Type,IMSBuildDataObject> col;
+ if (!customDataObjects.TryGetValue (owner, out col))
+ return default(T);
+ IMSBuildDataObject res;
+ col.TryGetValue (typeof(T), out res);
+ return (T)res;
+ }
+
+ internal void SetObject<T> (object owner, T t) where T : IMSBuildDataObject
+ {
+ Dictionary<Type,IMSBuildDataObject> col;
+ if (!customDataObjects.TryGetValue (owner, out col))
+ col = customDataObjects [owner] = new Dictionary<Type, IMSBuildDataObject> ();
+ col [typeof(T)] = t;
+ }
+
+ internal IEnumerable<IMSBuildDataObject> GetDataObjects (object owner)
+ {
+ Dictionary<Type,IMSBuildDataObject> col;
+ if (!customDataObjects.TryGetValue (owner, out col))
+ return new IMSBuildDataObject[0];
+ else
+ return col.Values;
+ }
+
+ public abstract void AddNewImport (string name, MSBuildImport beforeImport = null);
+
+ public abstract void RemoveImport (MSBuildImport import);
+
+ public abstract IEnumerable<MSBuildImport> Imports { get; }
+
+ public MSBuildPropertyGroup GetGlobalPropertyGroup ()
+ {
+ return PropertyGroups.FirstOrDefault (p => string.IsNullOrEmpty (p.Condition));
+ }
+
+ public abstract MSBuildPropertyGroup AddNewPropertyGroup (MSBuildPropertyGroup beforeGroup = null);
+
+ public abstract void RemovePropertyGroup (MSBuildPropertyGroup grp);
+
+ public abstract IEnumerable<MSBuildItem> GetAllItems ();
+
+ public abstract IEnumerable<MSBuildItem> GetAllItems (params string[] names);
+
+ public abstract IEnumerable<MSBuildPropertyGroup> PropertyGroups { get; }
+
+ public abstract IEnumerable<MSBuildItemGroup> ItemGroups { get; }
+
+ public abstract MSBuildItemGroup AddNewItemGroup ();
+
+ public abstract MSBuildItem AddNewItem (string name, string include);
+
+ public MSBuildItemGroup FindBestGroupForItem (string itemName)
+ {
+ MSBuildItemGroup group;
+
+ if (bestGroups == null)
+ bestGroups = new Dictionary<string, MSBuildItemGroup> ();
+ else {
+ if (bestGroups.TryGetValue (itemName, out group))
+ return group;
+ }
+
+ foreach (MSBuildItemGroup grp in ItemGroups) {
+ foreach (MSBuildItem it in grp.Items) {
+ if (it.Name == itemName) {
+ bestGroups [itemName] = grp;
+ return grp;
+ }
+ }
+ }
+ group = AddNewItemGroup ();
+ bestGroups [itemName] = group;
+ return group;
+ }
+
+ public abstract XmlElement GetProjectExtensions (string section);
+
+ public abstract void SetProjectExtensions (string section, string value);
+
+ public abstract void RemoveProjectExtensions (string section);
+
+ public abstract void RemoveItem (MSBuildItem item);
+ }
+
+ public abstract class MSBuildItemGroup
+ {
+ internal MSBuildItemGroup (MSBuildProject parent)
+ {
+ Project = parent;
+ }
+
+ public abstract MSBuildItem AddNewItem (string name, string include);
+
+ public abstract IEnumerable<MSBuildItem> Items { get; }
+
+ public MSBuildProject Project { get; private set; }
+ }
+
+ public abstract class MSBuildPropertyGroup: MSBuildPropertySet
+ {
+ MSBuildProject project;
+
+ internal MSBuildPropertyGroup (MSBuildProject project): base (project)
+ {
+ this.project = project;
+ }
+
+ public abstract string Label { get; set; }
+ public abstract string Condition { get; set; }
+ }
+
+ internal interface IPropertySetImpl
+ {
+ bool HasProperty (string name);
+ MSBuildProperty GetProperty (string name, string condition = null);
+ MSBuildProperty AddProperty (string name, string condition = null);
+ bool RemoveProperty (MSBuildProperty prop);
+ bool RemoveProperty (string name);
+ void RemoveAllProperties ();
+ IEnumerable<MSBuildProperty> Properties { get; }
+ }
+
+ public abstract class MSBuildPropertySet: IMSBuildPropertySet
+ {
+ MSBuildProject project;
+ Dictionary<Type,IMSBuildDataObject> customDataObjects = new Dictionary<Type,IMSBuildDataObject> ();
+
+ internal MSBuildPropertySet (MSBuildProject project)
+ {
+ this.project = project;
+ }
+
+ internal abstract IPropertySetImpl PropertySet { get; }
+
+ public T GetObject<T> () where T : IMSBuildDataObject, new()
+ {
+ IMSBuildDataObject res;
+ customDataObjects.TryGetValue (typeof(T), out res);
+ return (T)res;
+ }
+
+ public void SetObject<T> (T t) where T : IMSBuildDataObject
+ {
+ customDataObjects [typeof(T)] = t;
+ }
+
+ internal void WriteDataObjects ()
+ {
+ foreach (IMSBuildDataObject ob in customDataObjects.Values)
+ ob.Write (this, project.Format);
+ }
+
+ public bool HasProperty (string name)
+ {
+ return PropertySet.HasProperty (name);
+ }
+
+ public MSBuildProperty GetProperty (string name, string condition = null)
+ {
+ return PropertySet.GetProperty (name, condition);
+ }
+
+ public MSBuildProperty AddProperty (string name, string condition = null)
+ {
+ return PropertySet.AddProperty (name, condition);
+ }
+
+ MSBuildProperty SafeGetProperty (string name, string condition)
+ {
+ var prop = GetProperty (name, condition);
+ if (prop == null) {
+ prop = GetProperty (name);
+ if (prop != null) {
+ prop.Condition = condition;
+ return prop;
+ }
+ }
+ return AddProperty (name, condition);
+ }
+
+ public void SetValue (string name, string value, string defaultValue = null, bool preserveExistingCase = false, bool isXmlValue = false, bool mergeToMainGroup = false, string condition = null)
+ {
+ var prop = SafeGetProperty (name, condition);
+ if (value == defaultValue) {
+ RemoveProperty (prop);
+ return;
+ }
+ prop.SetValue (value, preserveExistingCase, isXmlValue, mergeToMainGroup);
+ }
+
+ public void SetValue (string name, XmlElement elem, bool mergeToMainGroup = false, string condition = null)
+ {
+ SafeGetProperty (name, condition).SetValue (elem, mergeToMainGroup);
+ }
+
+ public void SetValue (string name, XElement elem, bool mergeToMainGroup = false, string condition = null)
+ {
+ SafeGetProperty (name, condition).SetValue (elem, mergeToMainGroup);
+ }
+
+ public void SetValue (string name, FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false, string condition = null)
+ {
+ SafeGetProperty (name, condition).SetValue (value, relativeToProject, relativeToPath, mergeToMainGroup);
+ }
+
+ public void SetValue (string name, bool value, bool? defaultValue = false, bool mergeToMainGroup = false, string condition = null)
+ {
+ SafeGetProperty (name, condition).SetValue (value, mergeToMainGroup);
+ }
+
+ public string GetValue (string name, string defaultValue = null)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetValue ();
+ else
+ return defaultValue;
+ }
+
+ public XElement GetXmlValue (string name)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return XElement.Parse (prop.GetValue ());
+ else
+ return null;
+ }
+
+ public FilePath GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetPathValue (relativeToProject, relativeToPath);
+ else
+ return defaultValue;
+ }
+
+ public bool TryGetPathValue (string name, out FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.TryGetPathValue (out value, relativeToProject, relativeToPath);
+ else {
+ value = defaultValue;
+ return value != default(FilePath);
+ }
+ }
+
+ public bool GetBoolValue (string name, bool defaultValue = false)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetBoolValue ();
+ else
+ return defaultValue;
+ }
+
+ public virtual bool RemoveProperty (string name)
+ {
+ return PropertySet.RemoveProperty (name);
+ }
+
+ public bool RemoveProperty (MSBuildProperty prop)
+ {
+ return PropertySet.RemoveProperty (prop);
+ }
+
+ public void RemoveAllProperties ()
+ {
+ PropertySet.RemoveAllProperties ();
+ }
+
+ public IEnumerable<MSBuildProperty> Properties {
+ get { return PropertySet.Properties; }
+ }
+ }
+
+ public interface IMSBuildPropertySet
+ {
+ T GetObject<T> () where T:IMSBuildDataObject, new();
+ void SetObject<T> (T t) where T:IMSBuildDataObject;
+
+ bool HasProperty (string name);
+ MSBuildProperty GetProperty (string name, string condition = null);
+ IEnumerable<MSBuildProperty> Properties { get; }
+
+ void SetValue (string name, string value, string defaultValue = null, bool preserveExistingCase = false, bool isXmlValue = false, bool mergeToMainGroup = false, string condition = null);
+ void SetValue (string name, XmlElement elem, bool mergeToMainGroup = false, string condition = null);
+ void SetValue (string name, XElement elem, bool mergeToMainGroup = false, string condition = null);
+ void SetValue (string name, FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false, string condition = null);
+ void SetValue (string name, bool value, bool? defaultValue = false, bool mergeToMainGroup = false, string condition = null);
+
+ string GetValue (string name, string defaultValue = null);
+ XElement GetXmlValue (string name);
+ FilePath GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath));
+ bool TryGetPathValue (string name, out FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath));
+ bool GetBoolValue (string name, bool defaultValue = false);
+
+ bool RemoveProperty (string name);
+ void RemoveAllProperties ();
+ }
+
+ public abstract class MSBuildImport
+ {
+ public abstract string Target { get; set; }
+
+ public abstract string Label { get; set; }
+
+ public abstract string Condition { get; set; }
+ }
+
+ public abstract class MSBuildProperty
+ {
+ MSBuildProject project;
+
+ internal MSBuildProperty (MSBuildProject project)
+ {
+ this.project = project;
+ }
+
+ public abstract string Name {
+ get;
+ }
+
+ public abstract string Condition { get; set; }
+
+ public void SetValue (string value, bool preserveExistingCase = false, bool isXmlValue = false, bool mergeToMainGroup = false)
+ {
+ if (value == null)
+ value = String.Empty;
+
+ if (preserveExistingCase) {
+ var current = GetPropertyValue ();
+ if (current != null) {
+ if (current.Equals (value, preserveExistingCase ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture))
+ return;
+ }
+ }
+ SetPropertyValue (value, isXmlValue);
+ }
+
+ public void SetValue (XmlElement elem, bool mergeToMainGroup = false)
+ {
+ SetPropertyValue (elem.OuterXml, true);
+ }
+
+ public void SetValue (XElement elem, bool mergeToMainGroup = false)
+ {
+ SetPropertyValue (elem.ToString (), true);
+ }
+
+ public void SetValue (FilePath value, bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false)
+ {
+ string baseDir = null;
+ if (relativeToProject) {
+ if (relativeToPath != default(FilePath))
+ throw new ArgumentException ("relativeToPath argument can't be used together with relativeToProject");
+ baseDir = project.BaseDirectory;
+ } else if (relativeToPath != null) {
+ baseDir = relativeToPath;
+ }
+ SetPropertyValue (MonoDevelop.Projects.Formats.MSBuild.MSBuildProjectService.ToMSBuildPath (baseDir, value), false);
+ }
+
+ public void SetValue (bool value, bool mergeToMainGroup = false)
+ {
+ SetPropertyValue (value ? "True" : "False", false);
+ }
+
+ public string GetValue ()
+ {
+ return GetPropertyValue ();
+ }
+
+ public XElement GetXmlValue ()
+ {
+ var val = GetPropertyValue ();
+ if (val == null)
+ return null;
+ return XElement.Parse (val);
+ }
+
+ public FilePath GetPathValue (bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var val = GetPropertyValue ();
+ string baseDir = null;
+ if (relativeToProject) {
+ if (relativeToPath != default(FilePath))
+ throw new ArgumentException ("relativeToPath argument can't be used together with relativeToProject");
+ baseDir = project.BaseDirectory;
+ } else if (relativeToPath != null) {
+ baseDir = relativeToPath;
+ }
+ return MonoDevelop.Projects.Formats.MSBuild.MSBuildProjectService.FromMSBuildPath (baseDir, val);
+ }
+
+ public bool TryGetPathValue (out FilePath value, bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var val = GetPropertyValue ();
+ string baseDir = null;
+ if (relativeToProject) {
+ if (relativeToPath != default(FilePath))
+ throw new ArgumentException ("relativeToPath argument can't be used together with relativeToProject");
+ baseDir = project.BaseDirectory;
+ } else if (relativeToPath != null) {
+ baseDir = relativeToPath;
+ }
+ string path;
+ var res = MonoDevelop.Projects.Formats.MSBuild.MSBuildProjectService.FromMSBuildPath (baseDir, val, out path);
+ value = path;
+ return res;
+ }
+
+ public bool GetBoolValue ()
+ {
+ var val = GetPropertyValue ();
+ return val.Equals ("true", StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ protected abstract void SetPropertyValue (string value, bool isXml);
+ protected abstract string GetPropertyValue ();
+ }
+
+ public abstract class MSBuildItem: MSBuildPropertySet
+ {
+ MSBuildProject project;
+
+ internal MSBuildItem (MSBuildProject project): base (project)
+ {
+ this.project = project;
+ }
+
+ public abstract string Include { get; }
+
+ public abstract string UnevaluatedInclude { get; }
+
+ public abstract string Name { get; }
+ }
+
+ public interface IMSBuildDataObject
+ {
+ void Read (IMSBuildPropertySet pset, MonoDevelop.Projects.Formats.MSBuild.MSBuildFileFormat format);
+ void Write (IMSBuildPropertySet pset, MonoDevelop.Projects.Formats.MSBuild.MSBuildFileFormat format);
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildPropertySet.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildPropertySet.cs
new file mode 100644
index 0000000000..83a96d9f4c
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/IMSBuildPropertySet.cs
@@ -0,0 +1,173 @@
+//
+// MSBuildPropertySet.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Linq;
+using System.IO;
+using System.Collections.Generic;
+using System.Xml;
+using System.Text;
+
+using Microsoft.Build.BuildEngine;
+using MonoDevelop.Core;
+using System.Xml.Linq;
+using System.Reflection;
+using MonoDevelop.Core.Serialization;
+using System.Globalization;
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+
+ public interface IMSBuildPropertySet
+ {
+ string Label { get; set; }
+ T GetObject<T> () where T:IMSBuildDataObject, new();
+ void SetObject<T> (T t) where T:IMSBuildDataObject;
+
+ bool HasProperty (string name);
+ MSBuildProperty GetProperty (string name);
+ IEnumerable<MSBuildProperty> Properties { get; }
+
+ void SetValue (string name, string value, string defaultValue = null, bool preserveExistingCase = false, bool mergeToMainGroup = false, string condition = null);
+ void SetValue (string name, FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false, string condition = null);
+ void SetValue (string name, object value, object defaultValue = null, bool mergeToMainGroup = false, string condition = null);
+
+ string GetValue (string name, string defaultValue = null);
+ FilePath GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath));
+ bool TryGetPathValue (string name, out FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath));
+ T GetValue<T> (string name);
+ T GetValue<T> (string name, T defaultValue);
+ object GetValue (string name, Type type, object defaultValue);
+
+ bool RemoveProperty (string name);
+ void RemoveAllProperties ();
+
+ void SetPropertyOrder (params string[] propertyNames);
+
+ MSBuildProject Project { get; }
+ }
+
+ public static class IMSBuildPropertySetExtensions
+ {
+ class PropInfo
+ {
+ public MemberInfo Member;
+ public ItemPropertyAttribute Attribute;
+ public bool MergeToMainGroup;
+
+ public Type ReturnType {
+ get { return (Member is FieldInfo) ? ((FieldInfo)Member).FieldType : ((PropertyInfo)Member).PropertyType; }
+ }
+ public object GetValue (object instance)
+ {
+ if (Member is FieldInfo)
+ return ((FieldInfo)Member).GetValue (instance);
+ else
+ return ((PropertyInfo)Member).GetValue (instance, null);
+ }
+ public void SetValue (object instance, object value)
+ {
+ if (Member is FieldInfo)
+ ((FieldInfo)Member).SetValue (instance, value);
+ else
+ ((PropertyInfo)Member).SetValue (instance, value, null);
+ }
+ public string Name {
+ get { return Attribute.Name ?? Member.Name; }
+ }
+ }
+
+ static Dictionary<Type,PropInfo[]> types = new Dictionary<Type, PropInfo[]> ();
+
+ static PropInfo[] GetMembers (Type type)
+ {
+ PropInfo[] pinfo;
+ if (types.TryGetValue (type, out pinfo))
+ return pinfo;
+
+ List<PropInfo> list = new List<PropInfo> ();
+
+ foreach (var m in type.GetMembers (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
+ if (m.DeclaringType != type)
+ continue;
+ if (!(m is FieldInfo) && !(m is PropertyInfo))
+ continue;
+ var attr = Attribute.GetCustomAttribute (m, typeof(ItemPropertyAttribute)) as ItemPropertyAttribute;
+ if (attr == null)
+ continue;
+ bool merge = Attribute.IsDefined (m, typeof(MergeToProjectAttribute));
+
+ list.Add (new PropInfo {
+ Member = m,
+ Attribute = attr,
+ MergeToMainGroup = merge
+ });
+ }
+ return types [type] = list.ToArray ();
+ }
+
+ public static void WriteObjectProperties (this IMSBuildPropertySet pset, object ob, Type typeToScan)
+ {
+ var props = GetMembers (typeToScan);
+ foreach (var prop in props) {
+ if (prop.ReturnType == typeof(FilePath)) {
+ var val = (FilePath)prop.GetValue (ob);
+ FilePath def = prop.Attribute.DefaultValue != null ? (string)prop.Attribute.DefaultValue : (string)null;
+ pset.SetValue (prop.Name, val, def, mergeToMainGroup: prop.MergeToMainGroup);
+ } else if (prop.Attribute is ProjectPathItemProperty && prop.ReturnType == typeof(string)) {
+ FilePath val = (string)prop.GetValue (ob);
+ FilePath def = prop.Attribute.DefaultValue != null ? (string)prop.Attribute.DefaultValue : (string)null;
+ pset.SetValue (prop.Name, val, def, mergeToMainGroup: prop.MergeToMainGroup);
+ } else if (prop.ReturnType == typeof(string)) {
+ pset.SetValue (prop.Name, (string)prop.GetValue (ob), (string)prop.Attribute.DefaultValue, prop.MergeToMainGroup);
+ } else {
+ pset.SetValue (prop.Name, prop.GetValue (ob), prop.Attribute.DefaultValue, prop.MergeToMainGroup);
+ }
+ }
+ }
+
+ public static void ReadObjectProperties (this IMSBuildPropertySet pset, object ob, Type typeToScan)
+ {
+ var props = GetMembers (typeToScan);
+ foreach (var prop in props) {
+ object readVal = null;
+ if (prop.ReturnType == typeof(FilePath)) {
+ FilePath def = prop.Attribute.DefaultValue != null ? (string)prop.Attribute.DefaultValue : (string)null;
+ readVal = pset.GetPathValue (prop.Name, def);
+ } else if (prop.Attribute is ProjectPathItemProperty && prop.ReturnType == typeof(string)) {
+ FilePath def = prop.Attribute.DefaultValue != null ? (string)prop.Attribute.DefaultValue : (string)null;
+ readVal = pset.GetPathValue (prop.Name, def);
+ readVal = readVal.ToString ();
+ } else if (prop.ReturnType == typeof(string)) {
+ readVal = pset.GetValue (prop.Name, (string)prop.Attribute.DefaultValue);
+ } else {
+ readVal = pset.GetValue (prop.Name, prop.ReturnType, prop.Attribute.DefaultValue);
+ }
+ prop.SetValue (ob, readVal);
+ }
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildEvaluationContext.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildEvaluationContext.cs
new file mode 100644
index 0000000000..c681f46c94
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildEvaluationContext.cs
@@ -0,0 +1,177 @@
+//
+// MSBuildEvaluationContext.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Linq;
+using System.IO;
+using System.Collections.Generic;
+using System.Xml;
+using System.Text;
+
+using Microsoft.Build.BuildEngine;
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+
+ public class MSBuildEvaluationContext: IExpressionContext
+ {
+ Dictionary<string,string> properties = new Dictionary<string, string> ();
+ bool allResolved;
+ MSBuildProject project;
+
+ public MSBuildEvaluationContext ()
+ {
+ }
+
+ internal void InitEvaluation (MSBuildProject project)
+ {
+ this.project = project;
+ SetPropertyValue ("MSBuildThisFile", Path.GetFileName (project.FileName));
+ SetPropertyValue ("MSBuildThisFileName", Path.GetFileNameWithoutExtension (project.FileName));
+ SetPropertyValue ("MSBuildThisFileDirectory", Path.GetDirectoryName (project.FileName) + Path.DirectorySeparatorChar);
+ SetPropertyValue ("MSBuildThisFileExtension", Path.GetExtension (project.FileName));
+ SetPropertyValue ("MSBuildThisFileFullPath", Path.GetFullPath (project.FileName));
+ SetPropertyValue ("VisualStudioReferenceAssemblyVersion", project.ToolsVersion + ".0.0");
+ }
+
+ public string GetPropertyValue (string name)
+ {
+ string val;
+ if (properties.TryGetValue (name, out val))
+ return val;
+ else
+ return Environment.GetEnvironmentVariable (name);
+ }
+
+ public void SetPropertyValue (string name, string value)
+ {
+ properties [name] = value;
+ }
+
+ public void ClearPropertyValue (string name)
+ {
+ properties.Remove (name);
+ }
+
+ public bool Evaluate (XmlElement source, out XmlElement result)
+ {
+ allResolved = true;
+ result = (XmlElement) EvaluateNode (source);
+ return allResolved;
+ }
+
+ XmlNode EvaluateNode (XmlNode source)
+ {
+ var elemSource = source as XmlElement;
+ if (elemSource != null) {
+ var elem = source.OwnerDocument.CreateElement (elemSource.Prefix, elemSource.LocalName, elemSource.NamespaceURI);
+ foreach (XmlAttribute attr in elemSource.Attributes)
+ elem.Attributes.Append ((XmlAttribute)EvaluateNode (attr));
+ foreach (XmlNode child in elemSource.ChildNodes)
+ elem.AppendChild (EvaluateNode (child));
+ return elem;
+ }
+
+ var attSource = source as XmlAttribute;
+ if (attSource != null) {
+ bool oldResolved = allResolved;
+ var att = source.OwnerDocument.CreateAttribute (attSource.Prefix, attSource.LocalName, attSource.NamespaceURI);
+ att.Value = Evaluate (attSource.Value);
+
+ // Condition attributes don't change the resolution status. Conditions are handled in the property and item objects
+ if (attSource.Name == "Condition")
+ allResolved = oldResolved;
+
+ return att;
+ }
+ var textSource = source as XmlText;
+ if (textSource != null) {
+ return source.OwnerDocument.CreateTextNode (Evaluate (textSource.InnerText));
+ }
+ return source.Clone ();
+ }
+
+ public bool Evaluate (string str, out string result)
+ {
+ allResolved = true;
+ result = Evaluate (str);
+ return allResolved;
+ }
+
+ string Evaluate (string str)
+ {
+ int i = str.IndexOf ("$(");
+ if (i == -1)
+ return str;
+
+ int last = 0;
+
+ StringBuilder sb = new StringBuilder ();
+ do {
+ sb.Append (str, last, i - last);
+ i += 2;
+ int j = str.IndexOf (")", i);
+ if (j == -1) {
+ allResolved = false;
+ return "";
+ }
+
+ string prop = str.Substring (i, j - i);
+ string val = GetPropertyValue (prop);
+ if (val == null) {
+ allResolved = false;
+ return "";
+ }
+
+ sb.Append (val);
+ last = j + 1;
+ i = str.IndexOf ("$(", last);
+ }
+ while (i != -1);
+
+ sb.Append (str, last, str.Length - last);
+ return sb.ToString ();
+ }
+
+ #region IExpressionContext implementation
+
+ public string EvaluateString (string value)
+ {
+ if (value.StartsWith ("$(") && value.EndsWith (")"))
+ return GetPropertyValue (value.Substring (2, value.Length - 3)) ?? value;
+ else
+ return value;
+ }
+
+ public string FullFileName {
+ get {
+ return project.FileName;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildFileFormat.cs
index 05314dfdb7..282f7c0b3d 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildFileFormat.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildFileFormat.cs
@@ -33,18 +33,24 @@ using System.IO;
using MonoDevelop.Core;
using MonoDevelop.Core.Assemblies;
using MonoDevelop.Projects.Extensions;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Formats.MSBuild
{
public abstract class MSBuildFileFormat: IFileFormat
{
- readonly SlnFileFormat slnFileFormat = new SlnFileFormat ();
+ readonly SlnFileFormat slnFileFormat;
+
+ protected MSBuildFileFormat ()
+ {
+ slnFileFormat = new SlnFileFormat (this);
+ }
public string Name {
get { return "MSBuild"; }
}
- public SlnFileFormat SlnFileFormat {
+ internal SlnFileFormat SlnFileFormat {
get { return slnFileFormat; }
}
@@ -70,7 +76,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
if (slnFileFormat.CanWriteFile (obj, this))
return slnFileFormat.GetValidFormatName (obj, fileName, this);
else {
- string ext = MSBuildProjectService.GetExtensionForItem ((SolutionEntityItem)obj);
+ string ext = MSBuildProjectService.GetExtensionForItem ((SolutionItem)obj);
if (!string.IsNullOrEmpty (ext))
return fileName.ChangeExtension ("." + ext);
else
@@ -82,7 +88,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
{
if (expectedType.IsAssignableFrom (typeof(Solution)) && slnFileFormat.CanReadFile (file, this))
return true;
- else if (expectedType.IsAssignableFrom (typeof(SolutionEntityItem))) {
+ else if (expectedType.IsAssignableFrom (typeof(SolutionItem))) {
if (!MSBuildProjectService.CanReadFile (file))
return false;
//TODO: check ProductVersion first
@@ -95,12 +101,12 @@ namespace MonoDevelop.Projects.Formats.MSBuild
{
if (slnFileFormat.CanWriteFile (obj, this)) {
Solution sol = (Solution) obj;
- foreach (SolutionEntityItem si in sol.GetAllSolutionItems<SolutionEntityItem> ())
+ foreach (SolutionItem si in sol.GetAllItems<SolutionItem> ())
if (!CanWriteFile (si))
return false;
return true;
}
- else if (obj is SolutionEntityItem) {
+ else if (obj is SolutionItem) {
DotNetProject p = obj as DotNetProject;
// Check the framework only if the project is not loading, since otherwise the
// project may not yet have the framework info set.
@@ -118,7 +124,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
{
if (obj is Solution) {
List<string> msg = new List<string> ();
- foreach (SolutionEntityItem si in ((Solution)obj).GetAllSolutionItems<SolutionEntityItem> ()) {
+ foreach (SolutionItem si in ((Solution)obj).GetAllItems<SolutionItem> ()) {
IEnumerable<string> ws = GetCompatibilityWarnings (si);
if (ws != null)
msg.AddRange (ws);
@@ -135,26 +141,21 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return null;
}
- public void WriteFile (FilePath file, object obj, IProgressMonitor monitor)
+ public async Task WriteFile (FilePath file, object obj, ProgressMonitor monitor)
{
if (slnFileFormat.CanWriteFile (obj, this)) {
- slnFileFormat.WriteFile (file, obj, this, true, monitor);
+ await slnFileFormat.WriteFile (file, obj, true, monitor);
} else {
- SolutionEntityItem item = (SolutionEntityItem) obj;
- if (!(item.ItemHandler is MSBuildProjectHandler))
- MSBuildProjectService.InitializeItemHandler (item);
- MSBuildProjectHandler handler = (MSBuildProjectHandler) item.ItemHandler;
- handler.SetSolutionFormat (this, false);
- handler.Save (monitor);
+ throw new NotSupportedException ();
}
}
- public object ReadFile (FilePath file, Type expectedType, MonoDevelop.Core.IProgressMonitor monitor)
+ public async Task<object> ReadFile (FilePath file, Type expectedType, MonoDevelop.Core.ProgressMonitor monitor)
{
if (slnFileFormat.CanReadFile (file, this))
- return slnFileFormat.ReadFile (file, this, monitor);
+ return await slnFileFormat.ReadFile (file, monitor);
else
- return MSBuildProjectService.LoadItem (monitor, file, null, null, null);
+ return await MSBuildProjectService.LoadItem (monitor, file, null, null, null);
}
public List<FilePath> GetItemFiles (object obj)
@@ -162,24 +163,17 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return new List<FilePath> ();
}
- public void ConvertToFormat (object obj)
+ public Task ConvertToFormat (object obj)
{
if (obj == null)
- return;
+ return Task.FromResult(0);
- MSBuildHandler handler;
- SolutionItem item = obj as SolutionItem;
+ SolutionFolderItem item = obj as SolutionFolderItem;
if (item != null) {
- handler = item.GetItemHandler() as MSBuildHandler;
- if (handler != null) {
- handler.SetSolutionFormat (this, true);
- return;
- }
+ item.SetSolutionFormat (this, true);
+ return Task.FromResult(0);
}
-
- MSBuildProjectService.InitializeItemHandler (item);
- handler = (MSBuildHandler) item.ItemHandler;
- handler.SetSolutionFormat (this, true);
+ return Task.FromResult (0);
}
public bool SupportsMixedFormats {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildHandler.cs
deleted file mode 100644
index 29e862cb26..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildHandler.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-// MSBuildHandler.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-//
-
-using System;
-using System.IO;
-using System.Collections;
-using System.Collections.Generic;
-using System.Reflection;
-using MonoDevelop.Core;
-using MonoDevelop.Core.Serialization;
-using MonoDevelop.Projects;
-using MonoDevelop.Projects.Extensions;
-
-namespace MonoDevelop.Projects.Formats.MSBuild
-{
- public class MSBuildHandler: ISolutionItemHandler
- {
- SolutionItem item;
- string typeGuid;
- string id;
- string[] slnProjectContent;
- DataItem customSlnData;
-
- internal List<string> UnresolvedProjectDependencies { get; set; }
-
- internal protected MSBuildHandler ()
- {
- }
-
- public MSBuildHandler (string typeGuid, string itemId)
- {
- Initialize (typeGuid, itemId);
- }
-
- internal void Initialize (string typeGuid, string itemId)
- {
- this.typeGuid = typeGuid;
- this.id = itemId;
- }
-
- // When set, it means this item is saved as part of a global solution save operation
- internal bool SavingSolution { get; set; }
-
- internal protected SolutionItem Item {
- get { return item; }
- set { item = value; }
- }
-
- public virtual bool SyncFileName {
- get { return true; }
- }
-
- public string TypeGuid {
- get {
- return typeGuid;
- }
- }
-
- internal string[] SlnProjectContent {
- get {
- return slnProjectContent;
- }
- set {
- slnProjectContent = value;
- }
- }
-
- public string ItemId {
- get {
- if (id == null)
- id = String.Format ("{{{0}}}", System.Guid.NewGuid ().ToString ().ToUpper ());
- return id;
- }
- set { id = value; }
- }
-
- internal MSBuildFileFormat SolutionFormat { get; private set; }
-
- internal virtual void SetSolutionFormat (MSBuildFileFormat format, bool converting)
- {
- SolutionFormat = format;
- }
-
- public virtual BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
- {
- throw new NotSupportedException ();
- }
-
- public void Save (IProgressMonitor monitor)
- {
- if (HasSlnData && !SavingSolution && Item.ParentSolution != null) {
- // The project has data that has to be saved in the solution, but the solution is not being saved. Do it now.
- monitor.BeginTask (null, 2);
- SaveItem (monitor);
- monitor.Step (1);
- Solution sol = Item.ParentSolution;
- SolutionFormat.SlnFileFormat.WriteFile (sol.FileName, sol, SolutionFormat, false, monitor);
- sol.NeedsReload = false;
- monitor.EndTask ();
- } else
- SaveItem (monitor);
- }
-
- protected virtual void SaveItem (MonoDevelop.Core.IProgressMonitor monitor)
- {
- throw new NotSupportedException ();
- }
-
- public virtual void OnModified (string hint)
- {
- }
-
- public virtual void Dispose ()
- {
- }
-
- public virtual bool HasSlnData {
- get { return false; }
- }
-
- public virtual DataItem WriteSlnData ()
- {
- return customSlnData;
- }
-
- public virtual void ReadSlnData (DataItem item)
- {
- customSlnData = item;
- }
-
- /// <summary>
- /// Gets a service instance of a given type
- /// </summary>
- /// <returns>
- /// The service.
- /// </returns>
- /// <param name='t'>
- /// Type of the service
- /// </param>
- /// <remarks>
- /// This method looks for an imlpementation of a service of the given type.
- /// </remarks>
- public virtual object GetService (Type t)
- {
- return null;
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImport.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImport.cs
new file mode 100644
index 0000000000..0948c2a0b9
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildImport.cs
@@ -0,0 +1,56 @@
+//
+// MSBuildImport.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Xml;
+
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+
+ public class MSBuildImport: MSBuildObject
+ {
+ string evaluatedProjectPath;
+
+ public MSBuildImport (XmlElement elem): base (elem)
+ {
+ }
+
+ public string Project {
+ get { return Element.GetAttribute ("Project"); }
+ set { Element.SetAttribute ("Project", value); }
+ }
+
+ public string EvaluatedProject {
+ get { return evaluatedProjectPath ?? Project; }
+ }
+
+ internal void SetEvalResult (string evaluatedProjectPath)
+ {
+ this.evaluatedProjectPath = evaluatedProjectPath;
+ }
+ }
+
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItem.cs
new file mode 100644
index 0000000000..9858088f45
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItem.cs
@@ -0,0 +1,152 @@
+//
+// MSBuildItem.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Xml;
+
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+ public class MSBuildItem: MSBuildObject, IMSBuildItemEvaluated
+ {
+ MSBuildPropertyGroup metadata;
+ MSBuildPropertyGroupEvaluated evaluatedMetadata;
+ MSBuildProject parent;
+ string evaluatedInclude;
+
+ internal MSBuildItem (MSBuildProject parent, XmlElement elem): base (elem)
+ {
+ this.parent = parent;
+ }
+
+ public string Include {
+ get { return evaluatedInclude ?? UnevaluatedInclude; }
+ set { evaluatedInclude = UnevaluatedInclude = value; }
+ }
+
+ public string UnevaluatedInclude {
+ get { return Element.GetAttribute ("Include"); }
+ set { Element.SetAttribute ("Include", value); }
+ }
+
+ internal void SetEvalResult (string value)
+ {
+ this.evaluatedInclude = value;
+ }
+
+ public bool IsImported {
+ get;
+ set;
+ }
+
+ public string Name {
+ get { return Element.Name; }
+ }
+
+ public IMSBuildPropertySet Metadata {
+ get {
+ if (metadata == null) {
+ metadata = new MSBuildPropertyGroup (parent, Element);
+ metadata.UppercaseBools = true;
+ }
+ return metadata;
+ }
+ }
+
+ public IMSBuildPropertyGroupEvaluated EvaluatedMetadata {
+ get {
+ if (evaluatedMetadata == null)
+ evaluatedMetadata = new MSBuildPropertyGroupEvaluated (parent);
+ return evaluatedMetadata;
+ }
+ }
+
+ IMSBuildPropertyGroupEvaluated IMSBuildItemEvaluated.Metadata {
+ get { return EvaluatedMetadata; }
+ }
+
+ public void WriteDataObjects ()
+ {
+ metadata.WriteDataObjects ();
+ if (!Element.HasChildNodes)
+ Element.IsEmpty = true;
+ }
+ }
+
+ class MSBuildItemEvaluated: MSBuildObject, IMSBuildItemEvaluated
+ {
+ MSBuildPropertyGroupEvaluated metadata;
+ MSBuildProject parent;
+ string evaluatedInclude;
+ string include;
+
+ internal MSBuildItemEvaluated (MSBuildProject parent, string name, string include, string evaluatedInclude): base (null)
+ {
+ this.include = include;
+ this.evaluatedInclude = evaluatedInclude;
+ this.parent = parent;
+ Name = name;
+ }
+
+ public string Include {
+ get { return evaluatedInclude; }
+ }
+
+ public string UnevaluatedInclude {
+ get { return include; }
+ }
+
+ public bool IsImported {
+ get;
+ internal set;
+ }
+
+ public string Name { get; private set; }
+
+ public IMSBuildPropertyGroupEvaluated Metadata {
+ get {
+ if (metadata == null)
+ metadata = new MSBuildPropertyGroupEvaluated (parent);
+ return metadata;
+ }
+ }
+ }
+
+
+ public interface IMSBuildItemEvaluated
+ {
+ string Include { get; }
+
+ string UnevaluatedInclude { get; }
+
+ string Condition { get; }
+
+ bool IsImported { get; }
+
+ string Name { get; }
+
+ IMSBuildPropertyGroupEvaluated Metadata { get; }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItemGroup.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItemGroup.cs
new file mode 100644
index 0000000000..5f1a2eab17
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildItemGroup.cs
@@ -0,0 +1,73 @@
+//
+// MSBuildItemGroup.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Collections.Generic;
+using System.Xml;
+
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+
+ public class MSBuildItemGroup: MSBuildObject
+ {
+ MSBuildProject parent;
+
+ internal MSBuildItemGroup (MSBuildProject parent, XmlElement elem): base (elem)
+ {
+ this.parent = parent;
+ }
+
+ public bool IsImported {
+ get;
+ set;
+ }
+
+ public MSBuildItem AddNewItem (string name, string include)
+ {
+ XmlElement elem = AddChildElement (name);
+ MSBuildItem it = parent.GetItem (elem);
+ it.Include = include;
+ return it;
+ }
+
+ public IEnumerable<MSBuildItem> Items {
+ get {
+ foreach (XmlNode node in Element.ChildNodes) {
+ XmlElement elem = node as XmlElement;
+ if (elem != null)
+ yield return parent.GetItem (elem);
+ }
+ }
+ }
+
+ internal override void Evaluate (MSBuildEvaluationContext context)
+ {
+ foreach (var item in Items)
+ item.Evaluate (context);
+ }
+ }
+
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildObject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildObject.cs
new file mode 100644
index 0000000000..4c74f54285
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildObject.cs
@@ -0,0 +1,75 @@
+//
+// MSBuildObject.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Xml;
+
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+
+ public class MSBuildObject
+ {
+ XmlElement elem;
+
+ public MSBuildObject (XmlElement elem)
+ {
+ this.elem = elem;
+ }
+
+ public XmlElement Element {
+ get { return elem; }
+ }
+
+ protected XmlElement AddChildElement (string name)
+ {
+ XmlElement e = elem.OwnerDocument.CreateElement (null, name, MSBuildProject.Schema);
+ elem.AppendChild (e);
+ return e;
+ }
+
+ public string Label {
+ get { return Element.GetAttribute ("Label"); }
+ set { Element.SetAttribute ("Label", value); }
+ }
+
+ public string Condition {
+ get {
+ return Element != null ? Element.GetAttribute ("Condition") : null;
+ }
+ set {
+ if (string.IsNullOrEmpty (value))
+ Element.RemoveAttribute ("Condition");
+ else
+ Element.SetAttribute ("Condition", value);
+ }
+ }
+
+ internal virtual void Evaluate (MSBuildEvaluationContext context)
+ {
+ }
+ }
+
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs
index 2976287a16..4674d3f027 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs
@@ -26,33 +26,39 @@
//
using System;
-using System.Linq;
using System.IO;
using System.Collections.Generic;
using System.Xml;
using System.Text;
+using MonoDevelop.Core;
using MonoDevelop.Projects.Utility;
-using MonoDevelop.Projects.Text;
using Microsoft.Build.BuildEngine;
+using MSProject = Microsoft.Build.BuildEngine.Project;
+using System.Linq;
+using MonoDevelop.Projects.Text;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Formats.MSBuild
{
public class MSBuildProject
{
XmlDocument doc;
- string file;
+ FilePath file;
Dictionary<XmlElement,MSBuildObject> elemCache = new Dictionary<XmlElement,MSBuildObject> ();
Dictionary<string, MSBuildItemGroup> bestGroups;
-
+ List<MSBuildItemEvaluated> evaluatedItems = new List<MSBuildItemEvaluated> ();
+ List<MSBuildItemEvaluated> evaluatedItemsIgnoringCondition;
+ MSBuildEvaluatedPropertyCollection evaluatedProperties;
+
public const string Schema = "http://schemas.microsoft.com/developer/msbuild/2003";
static XmlNamespaceManager manager;
bool endsWithEmptyLine;
string newLine = Environment.NewLine;
ByteOrderMark bom;
-
- internal static XmlNamespaceManager XmlNamespaceManager {
+
+ public static XmlNamespaceManager XmlNamespaceManager {
get {
if (manager == null) {
manager = new XmlNamespaceManager (new NameTable ());
@@ -62,9 +68,21 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
}
- public string FileName {
+ public FilePath FileName {
get { return file; }
+ set { file = value; }
+ }
+
+ public FilePath BaseDirectory {
+ get { return file.ParentDirectory; }
}
+
+ public MSBuildFileFormat Format {
+ get;
+ set;
+ }
+
+ public bool IsNewProject { get; private set; }
public XmlDocument Document {
get { return doc; }
@@ -72,14 +90,27 @@ namespace MonoDevelop.Projects.Formats.MSBuild
public MSBuildProject ()
{
+ evaluatedProperties = new MSBuildEvaluatedPropertyCollection (this);
+ evaluatedItemsIgnoringCondition = new List<MSBuildItemEvaluated> ();
doc = new XmlDocument ();
doc.PreserveWhitespace = false;
doc.AppendChild (doc.CreateElement (null, "Project", Schema));
+ IsNewProject = true;
+ }
+
+ public static Task<MSBuildProject> LoadAsync (string file)
+ {
+ return Task<MSBuildProject>.Factory.StartNew (delegate {
+ var p = new MSBuildProject ();
+ p.Load (file);
+ return p;
+ });
}
public void Load (string file)
{
this.file = file;
+ IsNewProject = false;
using (FileStream fs = File.OpenRead (file)) {
byte[] buf = new byte [1024];
int nread, i;
@@ -172,18 +203,87 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return content;
}
+ void WriteDataObjects ()
+ {
+ foreach (var ob in elemCache.Values) {
+ if (ob is MSBuildPropertyGroup)
+ ((MSBuildPropertyGroup)ob).WriteDataObjects ();
+ else if (ob is MSBuildItem)
+ ((MSBuildItem)ob).WriteDataObjects ();
+ }
+ }
+
public void Evaluate ()
{
- Evaluate (new MSBuildEvaluationContext ());
+ try {
+ Engine e = new Engine ();
+ MSProject project = new MSProject (e);
+ project.Load (FileName);
+ SyncBuildProject (project);
+ } catch (Exception ex) {
+ // If the project can't be evaluated don't crash
+ LoggingService.LogError ("MSBuild project could not be evaluated", ex);
+ }
}
- public void Evaluate (MSBuildEvaluationContext context)
+ void SyncBuildProject (MSProject project)
{
- context.InitEvaluation (this);
- foreach (var pg in PropertyGroups)
- pg.Evaluate (context);
- foreach (var pg in ItemGroups)
- pg.Evaluate (context);
+ var xmlGroups = PropertyGroups.ToArray ();
+ var buildGroups = project.PropertyGroups.Cast<BuildPropertyGroup> ().ToArray ();
+ for (int n=0; n<xmlGroups.Length && n<buildGroups.Length; n++)
+ SyncBuildPropertyGroup (xmlGroups [n], buildGroups [n]);
+
+ var xmlItems = ItemGroups.ToArray ();
+ var buildItems = project.ItemGroups.Cast<BuildItemGroup> ().Where (g => !g.IsImported).ToArray ();
+ for (int n=0; n<xmlItems.Length && n<buildItems.Length; n++)
+ SyncBuildItemGroup (xmlItems [n], buildItems [n]);
+
+ var xmlImports = Imports.ToArray ();
+ var buildImports = project.Imports.Cast<Import> ().ToArray ();
+ for (int n = 0; n < xmlImports.Length && n < buildImports.Length; n++)
+ xmlImports [n].SetEvalResult (buildImports [n].EvaluatedProjectPath);
+
+ foreach (BuildItem it in project.EvaluatedItems) {
+ var xit = new MSBuildItemEvaluated (this, it.Name, it.Include, it.FinalItemSpec);
+ xit.IsImported = it.IsImported;
+ ((MSBuildPropertyGroupEvaluated)xit.Metadata).Sync (it);
+ evaluatedItems.Add (xit);
+ }
+
+ foreach (BuildItem it in project.EvaluatedItemsIgnoringCondition) {
+ var xit = new MSBuildItemEvaluated (this, it.Name, it.Include, it.FinalItemSpec);
+ xit.IsImported = it.IsImported;
+ ((MSBuildPropertyGroupEvaluated)xit.Metadata).Sync (it);
+ evaluatedItemsIgnoringCondition.Add (xit);
+ }
+
+ evaluatedProperties.Sync (project.EvaluatedProperties);
+ }
+
+ void SyncBuildPropertyGroup (MSBuildPropertyGroup xmlGroup, BuildPropertyGroup buildGroup)
+ {
+ var xmlProps = xmlGroup.Properties.ToArray ();
+ var buildProps = buildGroup.Cast<BuildProperty> ().ToArray ();
+ for (int n = 0; n < xmlProps.Length && n < buildProps.Length; n++)
+ SyncBuildProperty (xmlProps [n], buildProps [n]);
+ }
+
+ void SyncBuildProperty (MSBuildProperty xmlProp, BuildProperty buildProp)
+ {
+ }
+
+ void SyncBuildItemGroup (MSBuildItemGroup xmlGroup, BuildItemGroup buildGroup)
+ {
+ var xmlItems = xmlGroup.Items.ToArray ();
+ var buildItems = buildGroup.Cast<BuildItem> ().ToArray ();
+ for (int n = 0; n < xmlItems.Length && n < buildItems.Length; n++)
+ SyncBuildItem (xmlItems [n], buildItems [n]);
+ }
+
+ void SyncBuildItem (MSBuildItem xmlItem, BuildItem buildItem)
+ {
+ xmlItem.SetEvalResult (buildItem.FinalItemSpec);
+ ((MSBuildPropertyGroupEvaluated)xmlItem.EvaluatedMetadata).Sync (buildItem);
}
public string DefaultTargets {
@@ -200,11 +300,43 @@ namespace MonoDevelop.Projects.Formats.MSBuild
doc.DocumentElement.RemoveAttribute ("ToolsVersion");
}
}
+
+ public string[] ProjectTypeGuids {
+ get { return GetGlobalPropertyGroup ().GetValue ("ProjectTypeGuids", "").Split (new []{';'}, StringSplitOptions.RemoveEmptyEntries).Select (t => t.Trim()).ToArray (); }
+ set { GetGlobalPropertyGroup ().SetValue ("ProjectTypeGuids", string.Join (";", value), preserveExistingCase:true); }
+ }
+
+ public bool AddProjectTypeGuid (string guid)
+ {
+ var guids = GetGlobalPropertyGroup ().GetValue ("ProjectTypeGuids", "").Trim ();
+ if (guids.IndexOf (guid, StringComparison.OrdinalIgnoreCase) == -1) {
+ if (!string.IsNullOrEmpty (guids))
+ guids += ";" + guid;
+ else
+ guids = guid;
+ GetGlobalPropertyGroup ().SetValue ("ProjectTypeGuids", guids, preserveExistingCase: true);
+ return true;
+ }
+ return false;
+ }
- public MSBuildImport AddNewImport (string name, MSBuildImport beforeImport = null)
+ public bool RemoveProjectTypeGuid (string guid)
+ {
+ var guids = ProjectTypeGuids;
+ var newGuids = guids.Where (g => !g.Equals (guid, StringComparison.OrdinalIgnoreCase)).ToArray ();
+ if (newGuids.Length != guids.Length) {
+ ProjectTypeGuids = newGuids;
+ return true;
+ } else
+ return false;
+ }
+
+ public MSBuildImport AddNewImport (string name, string condition = null, MSBuildImport beforeImport = null)
{
XmlElement elem = doc.CreateElement (null, "Import", MSBuildProject.Schema);
elem.SetAttribute ("Project", name);
+ if (condition != null)
+ elem.SetAttribute ("Condition", condition);
if (beforeImport != null) {
doc.DocumentElement.InsertBefore (elem, beforeImport.Element);
@@ -215,7 +347,12 @@ namespace MonoDevelop.Projects.Formats.MSBuild
else
doc.DocumentElement.AppendChild (elem);
}
- return new MSBuildImport (elem);
+ return GetImport (elem);
+ }
+
+ public MSBuildImport GetImport (string name, string condition = null)
+ {
+ return Imports.FirstOrDefault (i => i.Project == name && i.Condition == condition);
}
public void RemoveImport (string name)
@@ -228,21 +365,37 @@ namespace MonoDevelop.Projects.Formats.MSBuild
Console.WriteLine ("ppnf:");
}
+ public void RemoveImport (MSBuildImport import)
+ {
+ import.Element.ParentNode.RemoveChild (import.Element);
+ }
+
public IEnumerable<MSBuildImport> Imports {
get {
foreach (XmlElement elem in doc.DocumentElement.SelectNodes ("tns:Import", XmlNamespaceManager))
- yield return new MSBuildImport (elem);
+ yield return GetImport (elem);
}
}
-
- public MSBuildPropertySet GetGlobalPropertyGroup ()
+
+ public IMSBuildEvaluatedPropertyCollection EvaluatedProperties {
+ get { return evaluatedProperties; }
+ }
+
+ public IEnumerable<IMSBuildItemEvaluated> EvaluatedItems {
+ get { return evaluatedItems; }
+ }
+
+ public IEnumerable<IMSBuildItemEvaluated> EvaluatedItemsIgnoringCondition {
+ get { return evaluatedItemsIgnoringCondition; }
+ }
+
+ public IMSBuildPropertySet GetGlobalPropertyGroup ()
{
- MSBuildPropertyGroupMerged res = new MSBuildPropertyGroupMerged ();
foreach (MSBuildPropertyGroup grp in PropertyGroups) {
if (grp.Condition.Length == 0)
- res.Add (grp);
+ return grp;
}
- return res.GroupCount > 0 ? res : null;
+ return null;
}
public MSBuildPropertyGroup AddNewPropertyGroup (bool insertAtEnd)
@@ -336,31 +489,67 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return group;
}
- public string GetProjectExtensions (string section)
+ public XmlElement GetProjectExtension (string section)
{
- XmlElement elem = doc.DocumentElement.SelectSingleNode ("tns:ProjectExtensions/tns:" + section, XmlNamespaceManager) as XmlElement;
- if (elem != null)
- return elem.InnerXml;
- else
- return string.Empty;
+ return doc.DocumentElement.SelectSingleNode ("tns:ProjectExtensions/tns:" + section, XmlNamespaceManager) as XmlElement;
}
- public void SetProjectExtensions (string section, string value)
+ public XmlElement GetMonoDevelopProjectExtension (string section)
{
+ return doc.DocumentElement.SelectSingleNode ("tns:ProjectExtensions/tns:MonoDevelop/tns:Properties/tns:" + section, XmlNamespaceManager) as XmlElement;
+ }
+
+ public void SetProjectExtension (string section, XmlElement value)
+ {
+ if (value.OwnerDocument != doc)
+ value = (XmlElement)doc.ImportNode (value, true);
+
+ XmlElement elem = doc.DocumentElement ["ProjectExtensions", MSBuildProject.Schema];
+ if (elem == null) {
+ elem = doc.CreateElement (null, "ProjectExtensions", MSBuildProject.Schema);
+ doc.DocumentElement.AppendChild (elem);
+ }
+ XmlElement sec = elem [section];
+ if (sec == null)
+ elem.AppendChild (value);
+ else {
+ elem.InsertAfter (value, sec);
+ elem.RemoveChild (sec);
+ }
+ }
+
+ public void SetMonoDevelopProjectExtension (string section, XmlElement value)
+ {
+ if (value.OwnerDocument != doc)
+ value = (XmlElement)doc.ImportNode (value, true);
+
XmlElement elem = doc.DocumentElement ["ProjectExtensions", MSBuildProject.Schema];
if (elem == null) {
elem = doc.CreateElement (null, "ProjectExtensions", MSBuildProject.Schema);
doc.DocumentElement.AppendChild (elem);
}
+ var parent = elem;
+ elem = parent ["MonoDevelop", MSBuildProject.Schema];
+ if (elem == null) {
+ elem = doc.CreateElement (null, "MonoDevelop", MSBuildProject.Schema);
+ parent.AppendChild (elem);
+ }
+ parent = elem;
+ elem = parent ["Properties", MSBuildProject.Schema];
+ if (elem == null) {
+ elem = doc.CreateElement (null, "Properties", MSBuildProject.Schema);
+ parent.AppendChild (elem);
+ }
XmlElement sec = elem [section];
- if (sec == null) {
- sec = doc.CreateElement (null, section, MSBuildProject.Schema);
- elem.AppendChild (sec);
+ if (sec == null)
+ elem.AppendChild (value);
+ else {
+ elem.InsertAfter (value, sec);
+ elem.RemoveChild (sec);
}
- sec.InnerXml = value;
}
- public void RemoveProjectExtensions (string section)
+ public void RemoveProjectExtension (string section)
{
XmlElement elem = doc.DocumentElement.SelectSingleNode ("tns:ProjectExtensions/tns:" + section, XmlNamespaceManager) as XmlElement;
if (elem != null) {
@@ -371,6 +560,19 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
}
+ public void RemoveMonoDevelopProjectExtension (string section)
+ {
+ XmlElement elem = doc.DocumentElement.SelectSingleNode ("tns:ProjectExtensions/tns:MonoDevelop/tns:Properties/tns:" + section, XmlNamespaceManager) as XmlElement;
+ if (elem != null) {
+ do {
+ XmlElement parent = (XmlElement) elem.ParentNode;
+ parent.RemoveChild (elem);
+ elem = parent;
+ }
+ while (!elem.HasChildNodes);
+ }
+ }
+
public void RemoveItem (MSBuildItem item)
{
elemCache.Remove (item.Element);
@@ -383,12 +585,22 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
}
+ internal MSBuildImport GetImport (XmlElement elem)
+ {
+ MSBuildObject ob;
+ if (elemCache.TryGetValue (elem, out ob))
+ return (MSBuildImport) ob;
+ MSBuildImport it = new MSBuildImport (elem);
+ elemCache [elem] = it;
+ return it;
+ }
+
internal MSBuildItem GetItem (XmlElement elem)
{
MSBuildObject ob;
if (elemCache.TryGetValue (elem, out ob))
return (MSBuildItem) ob;
- MSBuildItem it = new MSBuildItem (elem);
+ MSBuildItem it = new MSBuildItem (this, elem);
elemCache [elem] = it;
return it;
}
@@ -420,628 +632,12 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
}
- public class MSBuildObject
- {
- XmlElement elem;
- XmlElement evaluatedElem;
- public MSBuildObject (XmlElement elem)
- {
- this.elem = elem;
- }
-
- public XmlElement Element {
- get { return elem; }
- }
-
- public XmlElement EvaluatedElement {
- get { return evaluatedElem ?? elem; }
- protected set { evaluatedElem = value; }
- }
-
- public bool IsEvaluated {
- get { return evaluatedElem != null; }
- }
-
- protected XmlElement AddChildElement (string name)
- {
- XmlElement e = elem.OwnerDocument.CreateElement (null, name, MSBuildProject.Schema);
- elem.AppendChild (e);
- return e;
- }
-
- public string Label {
- get { return EvaluatedElement.GetAttribute ("Label"); }
- set { Element.SetAttribute ("Label", value); }
- }
-
- public string Condition {
- get {
- return Element.GetAttribute ("Condition");
- }
- set {
- if (string.IsNullOrEmpty (value))
- Element.RemoveAttribute ("Condition");
- else
- Element.SetAttribute ("Condition", value);
- }
- }
-
- internal virtual void Evaluate (MSBuildEvaluationContext context)
- {
- }
- }
-
- public class MSBuildImport: MSBuildObject
- {
- public MSBuildImport (XmlElement elem): base (elem)
- {
- }
-
- public string Project {
- get { return EvaluatedElement.GetAttribute ("Project"); }
- set { Element.SetAttribute ("Project", value); }
- }
-
- public string Condition {
- get { return EvaluatedElement.GetAttribute ("Condition"); }
- set { Element.SetAttribute ("Condition", value); }
- }
- }
- public class MSBuildProperty: MSBuildObject
- {
- public MSBuildProperty (XmlElement elem): base (elem)
- {
- }
-
- public string Name {
- get { return Element.Name; }
- }
-
- internal bool Overwritten { get; set; }
-
- public string GetValue (bool isXml = false)
- {
- if (isXml)
- return EvaluatedElement.InnerXml;
- return EvaluatedElement.InnerText;
- }
-
- public void SetValue (string value, bool isXml = false)
- {
- if (isXml)
- Element.InnerXml = value;
- else
- Element.InnerText = value;
- }
-
- internal override void Evaluate (MSBuildEvaluationContext context)
- {
- EvaluatedElement = null;
-
- if (!string.IsNullOrEmpty (Condition)) {
- string cond;
- if (!context.Evaluate (Condition, out cond)) {
- // The value could not be evaluated, so if there is an existing value, it is not valid anymore
- context.ClearPropertyValue (Name);
- return;
- }
- if (!ConditionParser.ParseAndEvaluate (cond, context))
- return;
- }
-
- XmlElement elem;
-
- if (context.Evaluate (Element, out elem)) {
- EvaluatedElement = elem;
- context.SetPropertyValue (Name, GetValue ());
- } else {
- // The value could not be evaluated, so if there is an existing value, it is not valid anymore
- context.ClearPropertyValue (Name);
- }
- }
- }
- public interface MSBuildPropertySet
- {
- MSBuildProperty GetProperty (string name);
- IEnumerable<MSBuildProperty> Properties { get; }
- MSBuildProperty SetPropertyValue (string name, string value, bool preserveExistingCase, bool isXml = false);
- string GetPropertyValue (string name, bool isXml = false);
- bool RemoveProperty (string name);
- void RemoveAllProperties ();
- void UnMerge (MSBuildPropertySet baseGrp, ISet<string> propertiesToExclude);
- }
- class MSBuildPropertyGroupMerged: MSBuildPropertySet
- {
- List<MSBuildPropertyGroup> groups = new List<MSBuildPropertyGroup> ();
-
- public void Add (MSBuildPropertyGroup g)
- {
- groups.Add (g);
- }
-
- public int GroupCount {
- get { return groups.Count; }
- }
-
- public MSBuildProperty GetProperty (string name)
- {
- // Find property in reverse order, since the last set
- // value is the good one
- for (int n=groups.Count - 1; n >= 0; n--) {
- var g = groups [n];
- MSBuildProperty p = g.GetProperty (name);
- if (p != null)
- return p;
- }
- return null;
- }
-
- public MSBuildProperty SetPropertyValue (string name, string value, bool preserveExistingCase, bool isXml = false)
- {
- MSBuildProperty p = GetProperty (name);
- if (p != null) {
- if (!preserveExistingCase || !string.Equals (value, p.GetValue (isXml), StringComparison.OrdinalIgnoreCase)) {
- p.SetValue (value, isXml);
- }
- return p;
- }
- return groups [0].SetPropertyValue (name, value, preserveExistingCase, isXml);
- }
-
- public string GetPropertyValue (string name, bool isXml = false)
- {
- MSBuildProperty prop = GetProperty (name);
- return prop != null ? prop.GetValue (isXml) : null;
- }
-
- public bool RemoveProperty (string name)
- {
- bool found = false;
- foreach (var g in groups) {
- if (g.RemoveProperty (name)) {
- Prune (g);
- found = true;
- }
- }
- return found;
- }
-
- public void RemoveAllProperties ()
- {
- foreach (var g in groups) {
- g.RemoveAllProperties ();
- Prune (g);
- }
- }
-
- public void UnMerge (MSBuildPropertySet baseGrp, ISet<string> propertiesToExclude)
- {
- foreach (var g in groups) {
- g.UnMerge (baseGrp, propertiesToExclude);
- }
- }
-
- public IEnumerable<MSBuildProperty> Properties {
- get {
- foreach (var g in groups) {
- foreach (var p in g.Properties)
- yield return p;
- }
- }
- }
-
- void Prune (MSBuildPropertyGroup g)
- {
- if (g != groups [0] && !g.Properties.Any()) {
- // Remove this group since it's now empty
- g.Parent.RemoveGroup (g);
- }
- }
- }
- public class MSBuildPropertyGroup: MSBuildObject, MSBuildPropertySet
- {
- Dictionary<string,MSBuildProperty> properties = new Dictionary<string,MSBuildProperty> ();
- List<MSBuildProperty> propertyList = new List<MSBuildProperty> ();
- MSBuildProject parent;
-
- public MSBuildPropertyGroup (MSBuildProject parent, XmlElement elem): base (elem)
- {
- this.parent = parent;
-
- foreach (var pelem in Element.ChildNodes.OfType<XmlElement> ()) {
- MSBuildProperty prevSameName;
- if (properties.TryGetValue (pelem.Name, out prevSameName))
- prevSameName.Overwritten = true;
-
- var prop = new MSBuildProperty (pelem);
- propertyList.Add (prop);
- properties [pelem.Name] = prop; // If a property is defined more than once, we only care about the last registered value
- }
- }
-
- public MSBuildProject Parent {
- get {
- return this.parent;
- }
- }
-
- public MSBuildProperty GetProperty (string name)
- {
- MSBuildProperty prop;
- properties.TryGetValue (name, out prop);
- return prop;
- }
-
- public IEnumerable<MSBuildProperty> Properties {
- get {
- return propertyList.Where (p => !p.Overwritten);
- }
- }
-
- public MSBuildProperty SetPropertyValue (string name, string value, bool preserveExistingCase, bool isXml = false)
- {
- MSBuildProperty prop = GetProperty (name);
- if (prop == null) {
- XmlElement pelem = AddChildElement (name);
- prop = new MSBuildProperty (pelem);
- properties [name] = prop;
- propertyList.Add (prop);
- prop.SetValue (value, isXml);
- } else if (!preserveExistingCase || !string.Equals (value, prop.GetValue (isXml), StringComparison.OrdinalIgnoreCase)) {
- prop.SetValue (value, isXml);
- }
- return prop;
- }
-
- public string GetPropertyValue (string name, bool isXml = false)
- {
- MSBuildProperty prop = GetProperty (name);
- if (prop == null)
- return null;
- else
- return prop.GetValue (isXml);
- }
-
- public bool RemoveProperty (string name)
- {
- MSBuildProperty prop = GetProperty (name);
- if (prop != null) {
- properties.Remove (name);
- propertyList.Remove (prop);
- Element.RemoveChild (prop.Element);
- return true;
- }
- return false;
- }
-
- public void RemoveAllProperties ()
- {
- List<XmlNode> toDelete = new List<XmlNode> ();
- foreach (XmlNode node in Element.ChildNodes) {
- if (node is XmlElement)
- toDelete.Add (node);
- }
- foreach (XmlNode node in toDelete)
- Element.RemoveChild (node);
- properties.Clear ();
- propertyList.Clear ();
- }
-
- public void UnMerge (MSBuildPropertySet baseGrp, ISet<string> propsToExclude)
- {
- foreach (MSBuildProperty prop in baseGrp.Properties) {
- if (propsToExclude != null && propsToExclude.Contains (prop.Name))
- continue;
- MSBuildProperty thisProp = GetProperty (prop.Name);
- if (thisProp != null && prop.GetValue (true).Equals (thisProp.GetValue (true), StringComparison.OrdinalIgnoreCase))
- RemoveProperty (prop.Name);
- }
- }
-
- internal override void Evaluate (MSBuildEvaluationContext context)
- {
- if (!string.IsNullOrEmpty (Condition)) {
- string cond;
- if (!context.Evaluate (Condition, out cond)) {
- // The condition could not be evaluated. Clear all properties that this group defines
- // since we don't know if they will have a value or not
- foreach (var prop in Properties)
- context.ClearPropertyValue (prop.Name);
- return;
- }
- if (!ConditionParser.ParseAndEvaluate (cond, context))
- return;
- }
-
- foreach (var prop in propertyList)
- prop.Evaluate (context);
- }
-
- public override string ToString()
- {
- string s = "[MSBuildPropertyGroup:";
- foreach (MSBuildProperty prop in Properties)
- s += " " + prop.Name + "=" + prop.GetValue (true);
- return s + "]";
- }
-
- }
- public class MSBuildItem: MSBuildObject
- {
- public MSBuildItem (XmlElement elem): base (elem)
- {
- }
-
- public string Include {
- get { return EvaluatedElement.GetAttribute ("Include"); }
- set { Element.SetAttribute ("Include", value); }
- }
-
- public string UnevaluatedInclude {
- get { return Element.GetAttribute ("Include"); }
- set { Element.SetAttribute ("Include", value); }
- }
-
- public string Name {
- get { return Element.Name; }
- }
-
- public bool HasMetadata (string name)
- {
- return EvaluatedElement [name, MSBuildProject.Schema] != null;
- }
-
- public void SetMetadata (string name, bool value)
- {
- SetMetadata (name, value ? "True" : "False");
- }
-
- public void SetMetadata (string name, string value, bool isXml = false)
- {
- // Don't overwrite the metadata value if the new value is the same as the old
- // This will keep the old metadata string, which can contain property references
- if (GetMetadata (name, isXml) == value)
- return;
-
- XmlElement elem = Element [name, MSBuildProject.Schema];
- if (elem == null) {
- elem = AddChildElement (name);
- Element.AppendChild (elem);
- }
- if (isXml)
- elem.InnerXml = value;
- else
- elem.InnerText = value;
- }
-
- public void UnsetMetadata (string name)
- {
- XmlElement elem = Element [name, MSBuildProject.Schema];
- if (elem != null) {
- Element.RemoveChild (elem);
- if (!Element.HasChildNodes)
- Element.IsEmpty = true;
- }
- }
-
- public string GetMetadata (string name, bool isXml = false)
- {
- XmlElement elem = EvaluatedElement [name, MSBuildProject.Schema];
- if (elem != null)
- return isXml ? elem.InnerXml : elem.InnerText;
- else
- return null;
- }
-
- public bool? GetBoolMetadata (string name)
- {
- var val = GetMetadata (name);
- if (String.Equals (val, "False", StringComparison.OrdinalIgnoreCase))
- return false;
- if (String.Equals (val, "True", StringComparison.OrdinalIgnoreCase))
- return true;
- return null;
- }
-
- public bool GetMetadataIsFalse (string name)
- {
- return String.Compare (GetMetadata (name), "False", StringComparison.OrdinalIgnoreCase) == 0;
- }
-
- public void MergeFrom (MSBuildItem other)
- {
- foreach (XmlNode node in Element.ChildNodes) {
- if (node is XmlElement)
- SetMetadata (node.LocalName, node.InnerXml, true);
- }
- }
-
- internal override void Evaluate (MSBuildEvaluationContext context)
- {
- XmlElement elem;
- if (context.Evaluate (Element, out elem))
- EvaluatedElement = elem;
- else
- EvaluatedElement = null;
- }
- }
- public class MSBuildItemGroup: MSBuildObject
- {
- MSBuildProject parent;
-
- internal MSBuildItemGroup (MSBuildProject parent, XmlElement elem): base (elem)
- {
- this.parent = parent;
- }
-
- public MSBuildItem AddNewItem (string name, string include)
- {
- XmlElement elem = AddChildElement (name);
- MSBuildItem it = parent.GetItem (elem);
- it.Include = include;
- return it;
- }
-
- public IEnumerable<MSBuildItem> Items {
- get {
- foreach (XmlNode node in Element.ChildNodes) {
- XmlElement elem = node as XmlElement;
- if (elem != null)
- yield return parent.GetItem (elem);
- }
- }
- }
-
- internal override void Evaluate (MSBuildEvaluationContext context)
- {
- foreach (var item in Items)
- item.Evaluate (context);
- }
- }
- public class MSBuildEvaluationContext: IExpressionContext
- {
- Dictionary<string,string> properties = new Dictionary<string, string> ();
- bool allResolved;
- MSBuildProject project;
-
- public MSBuildEvaluationContext ()
- {
- }
-
- internal void InitEvaluation (MSBuildProject project)
- {
- this.project = project;
- SetPropertyValue ("MSBuildThisFile", Path.GetFileName (project.FileName));
- SetPropertyValue ("MSBuildThisFileName", Path.GetFileNameWithoutExtension (project.FileName));
- SetPropertyValue ("MSBuildThisFileDirectory", Path.GetDirectoryName (project.FileName) + Path.DirectorySeparatorChar);
- SetPropertyValue ("MSBuildThisFileExtension", Path.GetExtension (project.FileName));
- SetPropertyValue ("MSBuildThisFileFullPath", Path.GetFullPath (project.FileName));
- SetPropertyValue ("VisualStudioReferenceAssemblyVersion", project.ToolsVersion + ".0.0");
- }
-
- public string GetPropertyValue (string name)
- {
- string val;
- if (properties.TryGetValue (name, out val))
- return val;
- else
- return Environment.GetEnvironmentVariable (name);
- }
-
- public void SetPropertyValue (string name, string value)
- {
- properties [name] = value;
- }
-
- public void ClearPropertyValue (string name)
- {
- properties.Remove (name);
- }
-
- public bool Evaluate (XmlElement source, out XmlElement result)
- {
- allResolved = true;
- result = (XmlElement) EvaluateNode (source);
- return allResolved;
- }
-
- XmlNode EvaluateNode (XmlNode source)
- {
- var elemSource = source as XmlElement;
- if (elemSource != null) {
- var elem = source.OwnerDocument.CreateElement (elemSource.Prefix, elemSource.LocalName, elemSource.NamespaceURI);
- foreach (XmlAttribute attr in elemSource.Attributes)
- elem.Attributes.Append ((XmlAttribute)EvaluateNode (attr));
- foreach (XmlNode child in elemSource.ChildNodes)
- elem.AppendChild (EvaluateNode (child));
- return elem;
- }
-
- var attSource = source as XmlAttribute;
- if (attSource != null) {
- bool oldResolved = allResolved;
- var att = source.OwnerDocument.CreateAttribute (attSource.Prefix, attSource.LocalName, attSource.NamespaceURI);
- att.Value = Evaluate (attSource.Value);
-
- // Condition attributes don't change the resolution status. Conditions are handled in the property and item objects
- if (attSource.Name == "Condition")
- allResolved = oldResolved;
-
- return att;
- }
- var textSource = source as XmlText;
- if (textSource != null) {
- return source.OwnerDocument.CreateTextNode (Evaluate (textSource.InnerText));
- }
- return source.Clone ();
- }
-
- public bool Evaluate (string str, out string result)
- {
- allResolved = true;
- result = Evaluate (str);
- return allResolved;
- }
-
- string Evaluate (string str)
- {
- int i = str.IndexOf ("$(");
- if (i == -1)
- return str;
-
- int last = 0;
-
- StringBuilder sb = new StringBuilder ();
- do {
- sb.Append (str, last, i - last);
- i += 2;
- int j = str.IndexOf (")", i);
- if (j == -1) {
- allResolved = false;
- return "";
- }
-
- string prop = str.Substring (i, j - i);
- string val = GetPropertyValue (prop);
- if (val == null) {
- allResolved = false;
- return "";
- }
-
- sb.Append (val);
- last = j + 1;
- i = str.IndexOf ("$(", last);
- }
- while (i != -1);
-
- sb.Append (str, last, str.Length - last);
- return sb.ToString ();
- }
-
- #region IExpressionContext implementation
-
- public string EvaluateString (string value)
- {
- if (value.StartsWith ("$(") && value.EndsWith (")"))
- return GetPropertyValue (value.Substring (2, value.Length - 3)) ?? value;
- else
- return value;
- }
-
- public string FullFileName {
- get {
- return project.FileName;
- }
- }
-
- #endregion
- }
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectFromFile.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectFromFile.cs
new file mode 100644
index 0000000000..5dc76c4283
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectFromFile.cs
@@ -0,0 +1,324 @@
+//
+// MSBuildProjectFromFile.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using MSProject = Microsoft.Build.BuildEngine.Project;
+using Microsoft.Build.BuildEngine;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Projects.Formats.MSBuildInternal
+{
+ public class MSBuildProjectFromFile: MSBuildProject
+ {
+ MSProject project;
+ List<ImportData> imports = new List<ImportData> ();
+ List<MSBuildPropertyGroup> propertyGroups = new List<MSBuildPropertyGroup> ();
+
+ class ImportData: MSBuildImport
+ {
+ #region implemented abstract members of MSBuildImport
+
+ public override string Target { get; set; }
+
+ public override string Label { get; set; }
+
+ public override string Condition { get; set; }
+
+ #endregion
+ }
+
+ class ProperyGroupData: MSBuildPropertyGroup, IPropertySetImpl
+ {
+ public List<MSBuildProperty> Properties = new List<MSBuildProperty> ();
+
+ public ProperyGroupData (MSBuildProject project) : base (project)
+ {
+ }
+
+ internal override IPropertySetImpl PropertySet {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public override string Label { get; set; }
+
+ public override string Condition { get; set; }
+ }
+
+ class ItemGroupData: MSBuildItemGroup
+ {
+ public List<MSBuildItem> GroupItems = new List<MSBuildItem> ();
+
+ public ItemGroupData (MSBuildProject project): base (project)
+ {
+ }
+
+ public override MSBuildItem AddNewItem (string name, string include)
+ {
+ var it = new ItemData (Project, name, include, include);
+ GroupItems.Add (it);
+ return it;
+ }
+
+ public override IEnumerable<MSBuildItem> Items {
+ get {
+ return GroupItems;
+ }
+ }
+ }
+
+ class ItemData: MSBuildItem
+ {
+ string name;
+ string unevaluatedInclude;
+ string include;
+
+ public ItemData (MSBuildProject project, string name, string include, string unevaluatedInclude): base (project)
+ {
+ this.name = name;
+ this.include = include;
+ this.unevaluatedInclude = unevaluatedInclude;
+ }
+
+ internal override IPropertySetImpl PropertySet {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public override string Include {
+ get { return include; }
+ }
+
+ public override string UnevaluatedInclude {
+ get {
+ return unevaluatedInclude;
+ }
+ }
+
+ public override string Name {
+ get {
+ return name;
+ }
+ }
+ }
+
+ class PropertyData: MSBuildProperty
+ {
+ public string Value;
+ public string RawValue;
+ string name;
+
+ public PropertyData (string name, MSBuildProject project) : base (project)
+ {
+ this.name = name;
+ }
+
+ public override string Name {
+ get { return name; }
+ }
+
+ protected override void SetPropertyValue (string value, bool isXml)
+ {
+ Value = value;
+ }
+
+ protected override string GetPropertyValue ()
+ {
+ return Value;
+ }
+
+ public override string Condition { get; set; }
+ }
+
+ public MSBuildProjectFromFile ()
+ {
+ }
+
+ #region IMSBuildProjectImpl implementation
+
+ public override void Load (MonoDevelop.Core.FilePath file)
+ {
+ foreach (Import im in project.Imports) {
+ imports.Add (new ImportData {
+ Condition = im.Condition
+ });
+ }
+ foreach (BuildPropertyGroup pg in project.PropertyGroups) {
+ var g = new ProperyGroupData (this) {
+ Condition = pg.Condition
+ };
+ foreach (BuildProperty p in pg) {
+ var prop = new PropertyData (p.Name, this) {
+ Value = p.FinalValue,
+ RawValue = p.Value
+ };
+ g.Properties.Add (prop);
+ }
+ propertyGroups.Add (g);
+ }
+ foreach (BuildItemGroup ig in project.ItemGroups) {
+
+ }
+ }
+
+ public override void AddNewImport (string name, MSBuildImport beforeImport = null)
+ {
+ var data = new ImportData {
+ Target = name
+ };
+ if (beforeImport != null) {
+ var other = (ImportData)beforeImport;
+ int i = imports.IndexOf (other);
+ if (i != -1) {
+ imports.Insert (i, data);
+ return;
+ }
+ }
+ imports.Add (data);
+ }
+
+ public override void RemoveImport (MSBuildImport import)
+ {
+ var data = (ImportData)import;
+ imports.Remove (data);
+ }
+
+ public override void Save (string fileName)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override string SaveToString ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override MSBuildPropertyGroup AddNewPropertyGroup (MSBuildPropertyGroup beforeGroup = null)
+ {
+ var g = new ProperyGroupData (this);
+ if (beforeGroup != null) {
+ var i = propertyGroups.IndexOf (beforeGroup);
+ if (i != -1) {
+ propertyGroups.Insert (i, g);
+ return g;
+ }
+ }
+ propertyGroups.Add (g);
+ return g;
+ }
+
+ public override void RemovePropertyGroup (MSBuildPropertyGroup grp)
+ {
+ propertyGroups.Remove (grp);
+ }
+
+ public override IEnumerable<MSBuildItem> GetAllItems ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override IEnumerable<MSBuildItem> GetAllItems (params string[] names)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override MSBuildItemGroup AddNewItemGroup ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override MSBuildItem AddNewItem (string name, string include)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override System.Xml.XmlElement GetProjectExtensions (string section)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void SetProjectExtensions (string section, string value)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void RemoveProjectExtensions (string section)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void RemoveItem (MSBuildItem item)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override MonoDevelop.Core.FilePath FileName {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public override string DefaultTargets {
+ get {
+ throw new NotImplementedException ();
+ }
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public override string ToolsVersion {
+ get {
+ throw new NotImplementedException ();
+ }
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public override IEnumerable<MSBuildImport> Imports {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public override IEnumerable<MSBuildPropertyGroup> PropertyGroups {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public override IEnumerable<MSBuildItemGroup> ItemGroups {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ #endregion
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs
index 96e68d4cef..7aded71f36 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs
@@ -41,2004 +41,10 @@ using Mono.Addins;
using System.Linq;
using MonoDevelop.Core.Instrumentation;
using MonoDevelop.Core.ProgressMonitoring;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Formats.MSBuild
{
- public class MSBuildProjectHandler: MSBuildHandler, IResourceHandler, IPathHandler, IAssemblyReferenceHandler
- {
- List<string> targetImports = new List<string> ();
- IResourceHandler customResourceHandler;
- List<string> subtypeGuids = new List<string> ();
- const string Unspecified = null;
- RemoteProjectBuilder projectBuilder;
- ITimeTracker timer;
- bool modifiedInMemory;
- UnknownProjectTypeNode unknownProjectTypeInfo;
-
- string lastBuildToolsVersion;
- string lastBuildRuntime;
- string lastFileName;
- string lastSlnFileName;
-
- struct ItemInfo {
- public MSBuildItem Item;
- public bool Added;
- }
-
- protected SolutionEntityItem EntityItem {
- get { return (SolutionEntityItem) Item; }
- }
-
- public string ToolsVersion { get; private set; }
- string productVersion;
- string schemaVersion;
-
- internal bool ProjectTypeIsUnsupported {
- get { return unknownProjectTypeInfo != null; }
- }
-
- internal UnknownProjectTypeNode UnknownProjectTypeInfo {
- get { return unknownProjectTypeInfo; }
- }
-
- public List<string> TargetImports {
- get { return targetImports; }
- }
-
- internal void SetUnsupportedType (UnknownProjectTypeNode typeInfo)
- {
- unknownProjectTypeInfo = typeInfo;
- }
-
- internal override void SetSolutionFormat (MSBuildFileFormat format, bool converting)
- {
- // when converting formats, set ToolsVersion, ProductVersion, SchemaVersion to default values written by VS
- // this happens on creation too
- // else we leave them alone and just roundtrip them
- if (converting) {
- ToolsVersion = format.DefaultToolsVersion;
- productVersion = format.DefaultProductVersion;
- schemaVersion = format.DefaultSchemaVersion;
- }
-
- base.SetSolutionFormat (format, converting);
- }
-
- //HACK: the solution's format is irrelevant to MSBuild projects, what matters is the ToolsVersion
- // but other parts of the MD API expect a FileFormat
- MSBuildFileFormat GetToolsFormat ()
- {
- switch (ToolsVersion) {
- case "2.0":
- return new MSBuildFileFormatVS05 ();
- case "3.5":
- return new MSBuildFileFormatVS08 ();
- case "4.0":
- if (SolutionFormat != null && SolutionFormat.Id == "MSBuild10")
- return SolutionFormat;
- return new MSBuildFileFormatVS12 ();
- case "12.0":
- return new MSBuildFileFormatVS12 ();
- default:
- throw new Exception ("Unknown ToolsVersion '" + ToolsVersion + "'");
- }
- }
-
- public void SetCustomResourceHandler (IResourceHandler value)
- {
- customResourceHandler = value;
- }
-
- public List<string> SubtypeGuids {
- get {
- return subtypeGuids;
- }
- }
-
- public MSBuildProjectHandler ()
- {
- }
-
- public MSBuildProjectHandler (string typeGuid, string import, string itemId)
- {
- Initialize (typeGuid, import, itemId);
- }
-
- internal void Initialize (string typeGuid, string import, string itemId)
- {
- base.Initialize (typeGuid, itemId);
- if (import != null && import.Trim().Length > 0)
- this.targetImports.AddRange (import.Split (':'));
-
- Runtime.SystemAssemblyService.DefaultRuntimeChanged += OnDefaultRuntimeChanged;
- }
-
- public override object GetService (Type t)
- {
- foreach (var ex in GetMSBuildExtensions ()) {
- var s = ex.GetService (t);
- if (s != null)
- return s;
- }
- return null;
- }
-
- void OnDefaultRuntimeChanged (object o, EventArgs args)
- {
- // If the default runtime changes, the project builder for this project may change
- // so it has to be created again.
- if (projectBuilder != null) {
- projectBuilder.Dispose ();
- projectBuilder = null;
- }
- }
-
- RemoteProjectBuilder GetProjectBuilder ()
- {
- var item = (SolutionEntityItem) Item;
-
- //FIXME: we can't really have per-project runtimes, has to be per-solution
- TargetRuntime runtime = null;
- var ap = item as IAssemblyProject;
- runtime = ap != null ? ap.TargetRuntime : Runtime.SystemAssemblyService.CurrentRuntime;
-
- var sln = item.ParentSolution;
- var slnFile = sln != null ? sln.FileName : null;
-
- if (projectBuilder == null || lastBuildToolsVersion != ToolsVersion || lastBuildRuntime != runtime.Id || lastFileName != item.FileName || lastSlnFileName != slnFile) {
- if (projectBuilder != null) {
- projectBuilder.Dispose ();
- projectBuilder = null;
- }
- projectBuilder = MSBuildProjectService.GetProjectBuilder (runtime, ToolsVersion, item.FileName, slnFile);
- lastBuildToolsVersion = ToolsVersion;
- lastBuildRuntime = runtime.Id;
- lastFileName = item.FileName;
- lastSlnFileName = slnFile;
- }
- else if (modifiedInMemory) {
- modifiedInMemory = false;
- var p = SaveProject (new NullProgressMonitor ());
- projectBuilder.RefreshWithContent (p.SaveToString ());
- }
- return projectBuilder;
- }
-
- void CleanupProjectBuilder ()
- {
- if (projectBuilder != null) {
- projectBuilder.Dispose ();
- projectBuilder = null;
- }
- }
-
- public override void Dispose ()
- {
- base.Dispose ();
- CleanupProjectBuilder ();
- Runtime.SystemAssemblyService.DefaultRuntimeChanged -= OnDefaultRuntimeChanged;
- }
-
- //for some reason, MD internally handles "AnyCPU" as "", but we need to be explicit when
- //passing it to the build engine
- static string GetExplicitPlatform (SolutionItemConfiguration configObject)
- {
- if (string.IsNullOrEmpty (configObject.Platform)) {
- return "AnyCPU";
- }
- return configObject.Platform;
- }
-
- ProjectConfigurationInfo[] GetConfigurations (SolutionEntityItem item, ConfigurationSelector configuration)
- {
- // Returns a list of project/configuration information for the provided item and all its references
- List<ProjectConfigurationInfo> configs = new List<ProjectConfigurationInfo> ();
- var c = item.GetConfiguration (configuration);
- configs.Add (new ProjectConfigurationInfo () {
- ProjectFile = item.FileName,
- Configuration = c.Name,
- Platform = GetExplicitPlatform (c)
- });
- foreach (var refProject in item.GetReferencedItems (configuration).OfType<Project> ()) {
- var refConfig = refProject.GetConfiguration (configuration);
- if (refConfig != null) {
- configs.Add (new ProjectConfigurationInfo () {
- ProjectFile = refProject.FileName,
- Configuration = refConfig.Name,
- Platform = GetExplicitPlatform (refConfig)
- });
- }
- }
- return configs.ToArray ();
- }
-
- IEnumerable<string> IAssemblyReferenceHandler.GetAssemblyReferences (ConfigurationSelector configuration)
- {
- if (UseMSBuildEngineForItem (Item, configuration)) {
- // Get the references list from the msbuild project
- SolutionEntityItem item = (SolutionEntityItem) Item;
- RemoteProjectBuilder builder = GetProjectBuilder ();
- var configs = GetConfigurations (item, configuration);
-
- var result = builder.Run (
- configs, null, MSBuildVerbosity.Normal,
- new[] { "ResolveAssemblyReferences" }, new [] { "ReferencePath" }, null
- );
-
- List<MSBuildEvaluatedItem> items;
- if (result.Items.TryGetValue ("ReferencePath", out items) && items != null) {
- foreach (var i in items)
- yield return i.ItemSpec;
- }
- }
- else {
- CleanupProjectBuilder ();
- DotNetProject item = Item as DotNetProject;
- if (item == null)
- yield break;
- foreach (ProjectReference pref in item.References.Where (pr => pr.ReferenceType != ReferenceType.Project)) {
- foreach (string asm in pref.GetReferencedFileNames (configuration))
- yield return asm;
- }
- }
- }
-
- public override BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
- {
- if (UseMSBuildEngineForItem (Item, configuration)) {
- SolutionEntityItem item = Item as SolutionEntityItem;
- if (item != null) {
- LogWriter logWriter = new LogWriter (monitor.Log);
- RemoteProjectBuilder builder = GetProjectBuilder ();
- var configs = GetConfigurations (item, configuration);
- var result = builder.Run (configs, logWriter, MSBuildProjectService.DefaultMSBuildVerbosity, new[] { target }, null, null);
- System.Runtime.Remoting.RemotingServices.Disconnect (logWriter);
-
- var br = new BuildResult ();
- foreach (var err in result.Errors) {
- FilePath file = null;
- if (err.File != null)
- file = Path.Combine (Path.GetDirectoryName (err.ProjectFile), err.File);
-
- if (err.IsWarning)
- br.AddWarning (file, err.LineNumber, err.ColumnNumber, err.Code, err.Message);
- else
- br.AddError (file, err.LineNumber, err.ColumnNumber, err.Code, err.Message);
- }
- return br;
- }
- }
- else {
- CleanupProjectBuilder ();
- if (Item is DotNetProject) {
- MD1DotNetProjectHandler handler = new MD1DotNetProjectHandler ((DotNetProject)Item);
- return handler.RunTarget (monitor, target, configuration);
- }
- }
- return null;
- }
-
- public string GetDefaultResourceId (ProjectFile file)
- {
- if (customResourceHandler != null)
- return customResourceHandler.GetDefaultResourceId (file);
- else
- return MSBuildResourceHandler.Instance.GetDefaultResourceId (file);
- }
-
- public string EncodePath (string path, string oldPath)
- {
- string basePath = Path.GetDirectoryName (EntityItem.FileName);
- return FileService.RelativeToAbsolutePath (basePath, path);
- }
-
- public string DecodePath (string path)
- {
- string basePath = Path.GetDirectoryName (EntityItem.FileName);
- return FileService.AbsoluteToRelativePath (basePath, path);
- }
-
- public SolutionEntityItem Load (IProgressMonitor monitor, string fileName, MSBuildFileFormat format, string language, Type itemClass)
- {
- timer = Counters.ReadMSBuildProject.BeginTiming ();
-
- timer.Trace ("Reading project file");
- MSBuildProject p = new MSBuildProject ();
- p.Load (fileName);
-
- ToolsVersion = p.ToolsVersion;
- if (string.IsNullOrEmpty (ToolsVersion))
- ToolsVersion = "2.0";
-
- SetSolutionFormat (format ?? new MSBuildFileFormatVS12 (), false);
-
- timer.Trace ("Read project guids");
-
- MSBuildPropertySet globalGroup = p.GetGlobalPropertyGroup ();
-
- // Avoid crash if there is not global group
- if (globalGroup == null)
- globalGroup = p.AddNewPropertyGroup (false);
-
- productVersion = globalGroup.GetPropertyValue ("ProductVersion");
- schemaVersion = globalGroup.GetPropertyValue ("SchemaVersion");
-
- string itemGuid = globalGroup.GetPropertyValue ("ProjectGuid");
- if (itemGuid == null)
- throw new UserException ("Project file doesn't have a valid ProjectGuid");
-
- // Workaround for a VS issue. VS doesn't include the curly braces in the ProjectGuid
- // of shared projects.
- if (!itemGuid.StartsWith ("{"))
- itemGuid = "{" + itemGuid + "}";
-
- itemGuid = itemGuid.ToUpper ();
- string projectTypeGuids = globalGroup.GetPropertyValue ("ProjectTypeGuids");
- string itemType = globalGroup.GetPropertyValue ("ItemType");
-
- subtypeGuids.Clear ();
- if (projectTypeGuids != null) {
- foreach (string guid in projectTypeGuids.Split (';')) {
- string sguid = guid.Trim ();
- if (sguid.Length > 0 && string.Compare (sguid, TypeGuid, true) != 0)
- subtypeGuids.Add (guid);
- }
- }
-
- try {
- timer.Trace ("Create item instance");
- ProjectExtensionUtil.BeginLoadOperation ();
- Item = CreateSolutionItem (monitor, p, fileName, language, itemType, itemClass);
-
- if (subtypeGuids.Any ()) {
- string gg = string.Join (";", subtypeGuids) + ";" + TypeGuid;
- Item.ExtendedProperties ["ProjectTypeGuids"] = gg.ToUpper ();
- }
-
- Item.SetItemHandler (this);
- MSBuildProjectService.SetId (Item, itemGuid);
-
- SolutionEntityItem it = (SolutionEntityItem) Item;
-
- it.FileName = fileName;
- it.Name = System.IO.Path.GetFileNameWithoutExtension (fileName);
-
- RemoveDuplicateItems (p, fileName);
-
- LoadProject (monitor, p);
- return it;
-
- } finally {
- ProjectExtensionUtil.EndLoadOperation ();
- timer.End ();
- }
- }
-
- /// <summary>Whether to use the MSBuild engine for the specified item.</summary>
- internal bool UseMSBuildEngineForItem (SolutionItem item, ConfigurationSelector sel, bool checkReferences = true)
- {
- // if the item mandates MSBuild, always use it
- if (RequireMSBuildEngine)
- return true;
- // if the user has set the option, use the setting
- if (item.UseMSBuildEngine.HasValue)
- return item.UseMSBuildEngine.Value;
-
- // If the item type defaults to using MSBuild, only use MSBuild if its direct references also use MSBuild.
- // This prevents a not-uncommon common error referencing non-MSBuild projects from MSBuild projects
- // NOTE: This adds about 11ms to the load/build/etc times of the MonoDevelop solution. Doing it recursively
- // adds well over a second.
- return UseMSBuildEngineByDefault && (
- !checkReferences ||
- item.GetReferencedItems (sel).All (i => {
- var h = i.ItemHandler as MSBuildProjectHandler;
- return h != null && h.UseMSBuildEngineForItem (i, sel, false);
- })
- );
- }
-
- /// <summary>Whether to use the MSBuild engine by default.</summary>
- internal bool UseMSBuildEngineByDefault { get; set; }
-
- /// <summary>Forces the MSBuild engine to be used.</summary>
- internal bool RequireMSBuildEngine { get; set; }
-
- // All of the last 4 parameters are optional, but at least one must be provided.
- SolutionItem CreateSolutionItem (IProgressMonitor monitor, MSBuildProject p, string fileName, string language,
- string itemType, Type itemClass)
- {
- if (ProjectTypeIsUnsupported)
- return new UnknownProject (fileName, UnknownProjectTypeInfo.GetInstructions ());
-
- if (subtypeGuids.Any ()) {
- DotNetProjectSubtypeNode st = MSBuildProjectService.GetDotNetProjectSubtype (subtypeGuids);
- if (st != null) {
- UseMSBuildEngineByDefault = st.UseXBuild;
- RequireMSBuildEngine = st.RequireXBuild;
- Type migratedType = null;
-
- if (st.IsMigration && (migratedType = MigrateProject (monitor, st, p, fileName, language)) != null) {
- var oldSt = st;
- st = MSBuildProjectService.GetItemSubtypeNodes ().Last (t => t.CanHandleType (migratedType));
-
- for (int i = 0; i < subtypeGuids.Count; i++) {
- if (string.Equals (subtypeGuids [i], oldSt.Guid, StringComparison.OrdinalIgnoreCase)) {
- subtypeGuids [i] = st.Guid;
- oldSt = null;
- break;
- }
- }
-
- if (oldSt != null)
- throw new Exception ("Unable to correct flavor GUID");
-
- var gg = string.Join (";", subtypeGuids) + ";" + TypeGuid;
- p.GetGlobalPropertyGroup ().SetPropertyValue ("ProjectTypeGuids", gg.ToUpper (), true);
- p.Save (fileName);
- }
-
- var item = st.CreateInstance (language);
- st.UpdateImports ((SolutionEntityItem)item, targetImports);
- return item;
- } else {
- var projectInfo = MSBuildProjectService.GetUnknownProjectTypeInfo (subtypeGuids.ToArray (), fileName);
- if (projectInfo != null && projectInfo.LoadFiles) {
- SetUnsupportedType (projectInfo);
- return new UnknownProject (fileName, UnknownProjectTypeInfo.GetInstructions ());
- }
- throw new UnknownSolutionItemTypeException (ProjectTypeIsUnsupported ? TypeGuid : string.Join (";", subtypeGuids));
- }
- }
-
- if (itemClass != null)
- return (SolutionItem) Activator.CreateInstance (itemClass);
-
- if (!string.IsNullOrEmpty (language)) {
- //enable msbuild by default .NET assembly projects
- UseMSBuildEngineByDefault = true;
- RequireMSBuildEngine = false;
- return new DotNetAssemblyProject (language);
- }
-
- if (string.IsNullOrEmpty (itemType))
- throw new UnknownSolutionItemTypeException ();
-
- DataType dt = MSBuildProjectService.DataContext.GetConfigurationDataType (itemType);
- if (dt == null)
- throw new UnknownSolutionItemTypeException (itemType);
-
- return (SolutionItem) Activator.CreateInstance (dt.ValueType);
- }
-
- Type MigrateProject (IProgressMonitor monitor, DotNetProjectSubtypeNode st, MSBuildProject p, string fileName, string language)
- {
- var projectLoadMonitor = monitor as IProjectLoadProgressMonitor;
- if (projectLoadMonitor == null) {
- // projectLoadMonitor will be null when running through md-tool, but
- // this is not fatal if migration is not required, so just ignore it. --abock
- if (!st.IsMigrationRequired)
- return null;
-
- LoggingService.LogError (Environment.StackTrace);
- monitor.ReportError ("Could not open unmigrated project and no migrator was supplied", null);
- throw new Exception ("Could not open unmigrated project and no migrator was supplied");
- }
-
- var migrationType = st.MigrationHandler.CanPromptForMigration
- ? st.MigrationHandler.PromptForMigration (projectLoadMonitor, p, fileName, language)
- : projectLoadMonitor.ShouldMigrateProject ();
- if (migrationType == MigrationType.Ignore) {
- if (st.IsMigrationRequired) {
- monitor.ReportError (string.Format ("{1} cannot open the project '{0}' unless it is migrated.", Path.GetFileName (fileName), BrandingService.ApplicationName), null);
- throw new Exception ("The user choose not to migrate the project");
- } else
- return null;
- }
-
- var baseDir = (FilePath) Path.GetDirectoryName (fileName);
- if (migrationType == MigrationType.BackupAndMigrate) {
- var backupDirFirst = baseDir.Combine ("backup");
- string backupDir = backupDirFirst;
- int i = 0;
- while (Directory.Exists (backupDir)) {
- backupDir = backupDirFirst + "-" + i.ToString ();
- if (i++ > 20) {
- throw new Exception ("Too many backup directories");
- }
- }
- Directory.CreateDirectory (backupDir);
- foreach (var file in st.MigrationHandler.FilesToBackup (fileName))
- File.Copy (file, Path.Combine (backupDir, Path.GetFileName (file)));
- }
-
- var type = st.MigrationHandler.Migrate (projectLoadMonitor, p, fileName, language);
- if (type == null)
- throw new Exception ("Could not migrate the project");
-
- return type;
- }
-
- FileFormat GetFileFormat (MSBuildFileFormat fmt)
- {
- return new FileFormat (fmt, fmt.Id, fmt.Name);
- }
-
- void RemoveDuplicateItems (MSBuildProject msproject, string fileName)
- {
- timer.Trace ("Checking for duplicate items");
-
- var uniqueIncludes = new Dictionary<string,object> ();
- var toRemove = new List<MSBuildItem> ();
- foreach (MSBuildItem bi in msproject.GetAllItems ()) {
- object existing;
- string key = bi.Name + "<" + bi.Include;
- if (!uniqueIncludes.TryGetValue (key, out existing)) {
- uniqueIncludes[key] = bi;
- continue;
- }
- var exBi = existing as MSBuildItem;
- if (exBi != null) {
- if (exBi.Condition != bi.Condition || exBi.Element.InnerXml != bi.Element.InnerXml) {
- uniqueIncludes[key] = new List<MSBuildItem> { exBi, bi };
- } else {
- toRemove.Add (bi);
- }
- continue;
- }
-
- var exList = (List<MSBuildItem>)existing;
- bool found = false;
- foreach (var m in (exList)) {
- if (m.Condition == bi.Condition && m.Element.InnerXml == bi.Element.InnerXml) {
- found = true;
- break;
- }
- }
- if (!found) {
- exList.Add (bi);
- } else {
- toRemove.Add (bi);
- }
- }
- if (toRemove.Count == 0)
- return;
-
- timer.Trace ("Removing duplicate items");
-
- foreach (var t in toRemove)
- msproject.RemoveItem (t);
-
- msproject.Save (fileName);
- }
-
- void LoadConfiguration (MSBuildSerializer serializer, List<ConfigData> configData, string conf, string platform)
- {
- MSBuildPropertySet grp = GetMergedConfiguration (configData, conf, platform, null);
- SolutionItemConfiguration config = EntityItem.CreateConfiguration (conf);
-
- config.Platform = platform;
- DataItem data = ReadPropertyGroupMetadata (serializer, grp, config);
- serializer.Deserialize (config, data);
- EntityItem.Configurations.Add (config);
-
- if (config is DotNetProjectConfiguration) {
- DotNetProjectConfiguration dpc = (DotNetProjectConfiguration) config;
- if (dpc.CompilationParameters != null) {
- data = ReadPropertyGroupMetadata (serializer, grp, dpc.CompilationParameters);
- serializer.Deserialize (dpc.CompilationParameters, data);
- }
- }
- }
-
- protected virtual void LoadProject (IProgressMonitor monitor, MSBuildProject msproject)
- {
- timer.Trace ("Initialize serialization");
-
- MSBuildSerializer ser = CreateSerializer ();
- ser.SerializationContext.BaseFile = EntityItem.FileName;
- ser.SerializationContext.ProgressMonitor = monitor;
-
- MSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup ();
-
- Item.SetItemHandler (this);
-
- DotNetProject dotNetProject = Item as DotNetProject;
-
- // Read all items
-
- timer.Trace ("Read project items");
-
- LoadProjectItems (msproject, ser, ProjectItemFlags.None);
-
- timer.Trace ("Read configurations");
-
- TargetFrameworkMoniker targetFx = null;
-
- if (dotNetProject != null) {
- string frameworkIdentifier = globalGroup.GetPropertyValue ("TargetFrameworkIdentifier");
- string frameworkVersion = globalGroup.GetPropertyValue ("TargetFrameworkVersion");
- string frameworkProfile = globalGroup.GetPropertyValue ("TargetFrameworkProfile");
-
- //determine the default target framework from the project type's default
- //overridden by the components in the project
- var def = dotNetProject.GetDefaultTargetFrameworkForFormat (GetFileFormat (GetToolsFormat ()));
- targetFx = new TargetFrameworkMoniker (
- string.IsNullOrEmpty (frameworkIdentifier)? def.Identifier : frameworkIdentifier,
- string.IsNullOrEmpty (frameworkVersion)? def.Version : frameworkVersion,
- string.IsNullOrEmpty (frameworkProfile)? def.Profile : frameworkProfile);
-
- if (dotNetProject.LanguageParameters != null) {
- DataItem data = ReadPropertyGroupMetadata (ser, globalGroup, dotNetProject.LanguageParameters);
- ser.Deserialize (dotNetProject.LanguageParameters, data);
- }
- }
-
- // Read configurations
-
- List<ConfigData> configData = GetConfigData (msproject, false);
- List<ConfigData> partialConfigurations = new List<ConfigData> ();
- HashSet<string> handledConfigurations = new HashSet<string> ();
- var configurations = new HashSet<string> ();
- var platforms = new HashSet<string> ();
-
- MSBuildPropertyGroup mergedToProjectProperties = ExtractMergedtoprojectProperties (ser, globalGroup, EntityItem.CreateConfiguration ("Dummy"));
- configData.Insert (0, new ConfigData (Unspecified, Unspecified, mergedToProjectProperties));
-
- // Load configurations, skipping the dummy config at index 0.
- for (int i = 1; i < configData.Count; i++) {
- ConfigData cgrp = configData[i];
- string platform = cgrp.Platform;
- string conf = cgrp.Config;
-
- if (platform != Unspecified)
- platforms.Add (platform);
-
- if (conf != Unspecified)
- configurations.Add (conf);
-
- if (conf == Unspecified || platform == Unspecified) {
- // skip partial configurations for now...
- partialConfigurations.Add (cgrp);
- continue;
- }
-
- string key = conf + "|" + platform;
- if (handledConfigurations.Contains (key))
- continue;
-
- LoadConfiguration (ser, configData, conf, platform);
-
- handledConfigurations.Add (key);
- }
-
- // Now we can load any partial configurations by combining them with known configs or platforms.
- if (partialConfigurations.Count > 0) {
- if (platforms.Count == 0)
- platforms.Add (string.Empty); // AnyCpu
-
- foreach (ConfigData cgrp in partialConfigurations) {
- if (cgrp.Config != Unspecified && cgrp.Platform == Unspecified) {
- string conf = cgrp.Config;
-
- foreach (var platform in platforms) {
- string key = conf + "|" + platform;
-
- if (handledConfigurations.Contains (key))
- continue;
-
- LoadConfiguration (ser, configData, conf, platform);
-
- handledConfigurations.Add (key);
- }
- } else if (cgrp.Config == Unspecified && cgrp.Platform != Unspecified) {
- string platform = cgrp.Platform;
-
- foreach (var conf in configurations) {
- string key = conf + "|" + platform;
-
- if (handledConfigurations.Contains (key))
- continue;
-
- LoadConfiguration (ser, configData, conf, platform);
-
- handledConfigurations.Add (key);
- }
- }
- }
- }
-
- // Read extended properties
-
- timer.Trace ("Read extended properties");
-
- DataItem globalData = ReadPropertyGroupMetadata (ser, globalGroup, Item);
-
- string extendedData = msproject.GetProjectExtensions ("MonoDevelop");
- if (!string.IsNullOrEmpty (extendedData)) {
- StringReader sr = new StringReader (extendedData);
- DataItem data = (DataItem) XmlConfigurationReader.DefaultReader.Read (new XmlTextReader (sr));
- globalData.ItemData.AddRange (data.ItemData);
- }
- ser.Deserialize (Item, globalData);
-
- // Final initializations
-
- timer.Trace ("Final initializations");
-
- //clean up the "InternalTargetFrameworkVersion" hack from MD 2.2, 2.4
- if (dotNetProject != null) {
- string fx = Item.ExtendedProperties ["InternalTargetFrameworkVersion"] as string;
- if (!string.IsNullOrEmpty (fx)) {
- targetFx = TargetFrameworkMoniker.Parse (fx);
- Item.ExtendedProperties.Remove ("InternalTargetFrameworkVersion");
- }
-
- dotNetProject.TargetFramework = Runtime.SystemAssemblyService.GetTargetFramework (targetFx);
- }
-
- LoadFromMSBuildProject (monitor, msproject);
-
- Item.NeedsReload = false;
- }
-
- internal void LoadProjectItems (MSBuildProject msproject, MSBuildSerializer ser, ProjectItemFlags flags)
- {
- foreach (MSBuildItem buildItem in msproject.GetAllItems ()) {
- ProjectItem it = ReadItem (ser, buildItem);
- if (it == null)
- continue;
- it.Flags = flags;
- if (it is ProjectFile) {
- var file = (ProjectFile)it;
- if (file.Name.IndexOf ('*') > -1) {
- // Thanks to IsOriginatedFromWildcard, these expanded items will not be saved back to disk.
- foreach (var expandedItem in ResolveWildcardItems (file))
- EntityItem.Items.Add (expandedItem);
- // Add to wildcard items (so it can be re-saved) instead of Items (where tools will
- // try to compile and display these nonstandard items
- EntityItem.WildcardItems.Add (it);
- continue;
- }
- if (ProjectTypeIsUnsupported && !File.Exists (file.FilePath))
- continue;
- }
- EntityItem.Items.Add (it);
- it.ExtendedProperties ["MSBuild.SourceProject"] = msproject.FileName;
- }
- }
-
- protected virtual void LoadFromMSBuildProject (IProgressMonitor monitor, MSBuildProject msproject)
- {
- foreach (var ext in GetMSBuildExtensions ())
- ext.LoadProject (monitor, EntityItem, msproject);
- }
-
- const string RecursiveDirectoryWildcard = "**";
- static readonly char[] directorySeparators = new [] {
- Path.DirectorySeparatorChar,
- Path.AltDirectorySeparatorChar
- };
-
- static string GetWildcardDirectoryName (string path)
- {
- int indexOfLast = path.LastIndexOfAny (directorySeparators);
- if (indexOfLast < 0)
- return String.Empty;
- return path.Substring (0, indexOfLast);
- }
-
- static string GetWildcardFileName (string path)
- {
- int indexOfLast = path.LastIndexOfAny (directorySeparators);
- if (indexOfLast < 0)
- return path;
- if (indexOfLast == path.Length)
- return String.Empty;
- return path.Substring (indexOfLast + 1, path.Length - (indexOfLast + 1));
- }
-
- static IEnumerable<string> ExpandWildcardFilePath (string filePath)
- {
- if (String.IsNullOrWhiteSpace (filePath))
- throw new ArgumentException ("Not a wildcard path");
-
- string dir = GetWildcardDirectoryName (filePath);
- string file = GetWildcardFileName (filePath);
-
- if (String.IsNullOrEmpty (dir) || String.IsNullOrEmpty (file))
- return null;
-
- SearchOption searchOption = SearchOption.TopDirectoryOnly;
- if (dir.EndsWith (RecursiveDirectoryWildcard, StringComparison.Ordinal)) {
- dir = dir.Substring (0, dir.Length - RecursiveDirectoryWildcard.Length);
- searchOption = SearchOption.AllDirectories;
- }
-
- if (!Directory.Exists (dir))
- return null;
-
- return Directory.GetFiles (dir, file, searchOption);
- }
-
- static IEnumerable<ProjectFile> ResolveWildcardItems (ProjectFile wildcardFile)
- {
- var paths = ExpandWildcardFilePath (wildcardFile.Name);
- if (paths == null)
- yield break;
- foreach (var resolvedFilePath in paths) {
- var projectFile = (ProjectFile)wildcardFile.Clone ();
- projectFile.Name = resolvedFilePath;
- projectFile.IsOriginatedFromWildcard = true;
- yield return projectFile;
- }
- }
-
- MSBuildPropertyGroup ExtractMergedtoprojectProperties (MSBuildSerializer ser, MSBuildPropertySet pgroup, SolutionItemConfiguration ob)
- {
- XmlDocument doc = new XmlDocument ();
- MSBuildPropertyGroup res = new MSBuildPropertyGroup (null, doc.CreateElement ("PropGroup"));
-
- // When reading a project, all configuration properties specified in the global property group have to
- // be merged with all project configurations, no matter if they have the MergeToProject attribute or not
-
- ClassDataType dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (ob.GetType ());
- foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, ob)) {
- MSBuildProperty bp = pgroup.GetProperty (prop.Name);
- if (bp != null) {
- var preserveCase = prop.DataType is MSBuildBoolDataType;
- res.SetPropertyValue (bp.Name, bp.Element.InnerXml, preserveCase, true);
- }
- }
- if (ob is DotNetProjectConfiguration) {
- object cparams = ((DotNetProjectConfiguration)ob).CompilationParameters;
- dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (cparams.GetType ());
- foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, cparams)) {
- MSBuildProperty bp = pgroup.GetProperty (prop.Name);
- if (bp != null) {
- var preserveCase = prop.DataType is MSBuildBoolDataType;
- res.SetPropertyValue (bp.Name, bp.Element.InnerXml, preserveCase, true);
- }
- }
- }
- return res;
- }
-
- IEnumerable<MergedProperty> GetMergeToProjectProperties (MSBuildSerializer ser, object ob)
- {
- ClassDataType dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (ob.GetType ());
- foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, ob)) {
- if (IsMergeToProjectProperty (prop)) {
- yield return new MergedProperty (prop.Name, prop.DataType is MSBuildBoolDataType);
- }
- }
- }
-
- struct MergedProperty
- {
- public readonly string Name;
- public readonly bool PreserveExistingCase;
-
- public MergedProperty (string name, bool preserveExistingCase)
- {
- this.Name = name;
- this.PreserveExistingCase = preserveExistingCase;
- }
- }
-
- internal ProjectItem ReadItem (MSBuildSerializer ser, MSBuildItem buildItem)
- {
- Project project = Item as Project;
- DotNetProject dotNetProject = Item as DotNetProject;
-
- DataType dt = ser.DataContext.GetConfigurationDataType (buildItem.Name);
-
- if (project != null) {
- if (buildItem.Name == "Folder") {
- // Read folders
- string path = MSBuildProjectService.FromMSBuildPath (project.ItemDirectory, buildItem.Include);
- return new ProjectFile () { Name = Path.GetDirectoryName (path), Subtype = Subtype.Directory };
- }
- else if (buildItem.Name == "Reference" && dotNetProject != null) {
- ProjectReference pref;
- if (buildItem.HasMetadata ("HintPath")) {
- string hintPath = buildItem.GetMetadata ("HintPath");
- string path;
- if (!MSBuildProjectService.FromMSBuildPath (dotNetProject.ItemDirectory, hintPath, out path)) {
- pref = new ProjectReference (ReferenceType.Assembly, path);
- pref.SetInvalid (GettextCatalog.GetString ("Invalid file path"));
- pref.ExtendedProperties ["_OriginalMSBuildReferenceInclude"] = buildItem.Include;
- pref.ExtendedProperties ["_OriginalMSBuildReferenceHintPath"] = hintPath;
- } else {
- var type = File.Exists (path) ? ReferenceType.Assembly : ReferenceType.Package;
- pref = new ProjectReference (type, buildItem.Include, path);
- pref.ExtendedProperties ["_OriginalMSBuildReferenceHintPath"] = hintPath;
- if (MSBuildProjectService.IsAbsoluteMSBuildPath (hintPath))
- pref.ExtendedProperties ["_OriginalMSBuildReferenceIsAbsolute"] = true;
- }
- } else {
- string asm = buildItem.Include;
- // This is a workaround for a VS bug. Looks like it is writing this assembly incorrectly
- if (asm == "System.configuration")
- asm = "System.Configuration";
- else if (asm == "System.XML")
- asm = "System.Xml";
- else if (asm == "system")
- asm = "System";
- pref = new ProjectReference (ReferenceType.Package, asm);
- }
- var privateCopy = buildItem.GetBoolMetadata ("Private");
- if (privateCopy != null)
- pref.LocalCopy = privateCopy.Value;
-
- pref.Condition = buildItem.Condition;
- string specificVersion = buildItem.GetMetadata ("SpecificVersion");
- if (string.IsNullOrWhiteSpace (specificVersion)) {
- // If the SpecificVersion element isn't present, check if the Assembly Reference specifies a Version
- pref.SpecificVersion = ReferenceStringHasVersion (buildItem.Include);
- }
- else {
- bool value;
- // if we can't parse the value, default to false which is more permissive
- pref.SpecificVersion = bool.TryParse (specificVersion, out value) && value;
- }
- ReadBuildItemMetadata (ser, buildItem, pref, typeof(ProjectReference));
- return pref;
- }
- else if (buildItem.Name == "ProjectReference" && dotNetProject != null) {
- // Get the project name from the path, since the Name attribute may other stuff other than the name
- string path = MSBuildProjectService.FromMSBuildPath (project.ItemDirectory, buildItem.Include);
- string name = Path.GetFileNameWithoutExtension (path);
- ProjectReference pref = new ProjectReference (ReferenceType.Project, name);
- pref.Condition = buildItem.Condition;
- var privateCopy = buildItem.GetBoolMetadata ("Private");
- if (privateCopy != null)
- pref.LocalCopy = privateCopy.Value;
- return pref;
- }
- else if (dt == null && !string.IsNullOrEmpty (buildItem.Include)) {
- // Unknown item. Must be a file.
- if (!UnsupportedItems.Contains (buildItem.Name) && IsValidFile (buildItem.Include))
- return ReadProjectFile (ser, project, buildItem, typeof(ProjectFile));
- }
- }
-
- // ProjectReference objects only make sense on a DotNetProject, so don't load them
- // if that's not the type of the project.
- if (dt != null && dt.ValueType == typeof(ProjectReference) && dotNetProject == null)
- dt = null;
-
- if (dt != null && typeof(ProjectItem).IsAssignableFrom (dt.ValueType)) {
- ProjectItem obj = (ProjectItem) Activator.CreateInstance (dt.ValueType);
- ReadBuildItemMetadata (ser, buildItem, obj, dt.ValueType);
- return obj;
- }
-
- UnknownProjectItem uitem = new UnknownProjectItem (buildItem.Name, "");
- ReadBuildItemMetadata (ser, buildItem, uitem, typeof(UnknownProjectItem));
-
- return uitem;
- }
-
- bool ReferenceStringHasVersion (string asmName)
- {
- int commaPos = asmName.IndexOf (',');
- return commaPos >= 0 && asmName.IndexOf ("Version", commaPos) >= 0;
- }
-
- bool IsValidFile (string path)
- {
- // If it is an absolute uri, it's not a valid file
- try {
- if (Uri.IsWellFormedUriString (path, UriKind.Absolute)) {
- var f = new Uri (path);
- return f.Scheme == "file";
- }
- } catch {
- // Old mono versions may crash in IsWellFormedUriString if the path
- // is not an uri.
- }
- return true;
- }
-
- class ConfigData
- {
- public ConfigData (string conf, string plt, MSBuildPropertyGroup grp)
- {
- Config = conf;
- Platform = plt;
- Group = grp;
- }
-
- public bool FullySpecified {
- get { return Config != Unspecified && Platform != Unspecified; }
- }
-
- public string Config;
- public string Platform;
- public MSBuildPropertyGroup Group;
- public bool Exists;
- public bool IsNew; // The group did not exist in the original file
- }
-
- MSBuildPropertySet GetMergedConfiguration (List<ConfigData> configData, string conf, string platform, MSBuildPropertyGroup propGroupLimit)
- {
- MSBuildPropertySet merged = null;
-
- foreach (ConfigData grp in configData) {
- if (grp.Group == propGroupLimit)
- break;
- if ((grp.Config == conf || grp.Config == Unspecified || conf == Unspecified) && (grp.Platform == platform || grp.Platform == Unspecified || platform == Unspecified)) {
- if (merged == null)
- merged = grp.Group;
- else if (merged is MSBuildPropertyGroupMerged)
- ((MSBuildPropertyGroupMerged)merged).Add (grp.Group);
- else {
- MSBuildPropertyGroupMerged m = new MSBuildPropertyGroupMerged ();
- m.Add ((MSBuildPropertyGroup)merged);
- m.Add (grp.Group);
- merged = m;
- }
- }
- }
- return merged;
- }
-
- bool ContainsSpecificPlatformConfiguration (List<ConfigData> configData, string conf)
- {
- foreach (ConfigData grp in configData) {
- if (grp.Config == conf && grp.Platform != Unspecified)
- return true;
- }
- return false;
- }
-
- public override void OnModified (string hint)
- {
- base.OnModified (hint);
- modifiedInMemory = true;
- }
-
- protected override void SaveItem (MonoDevelop.Core.IProgressMonitor monitor)
- {
- modifiedInMemory = false;
-
- MSBuildProject msproject = SaveProject (monitor);
- if (msproject == null)
- return;
-
- // Don't save the file to disk if the content did not change
- msproject.Save (EntityItem.FileName);
-
- if (projectBuilder != null)
- projectBuilder.Refresh ();
- }
-
- protected virtual MSBuildProject SaveProject (IProgressMonitor monitor)
- {
- if (Item is UnknownSolutionItem)
- return null;
-
- var toolsFormat = GetToolsFormat ();
-
- bool newProject;
- SolutionEntityItem eitem = EntityItem;
-
- MSBuildSerializer ser = CreateSerializer ();
- ser.SerializationContext.BaseFile = eitem.FileName;
- ser.SerializationContext.ProgressMonitor = monitor;
-
- DotNetProject dotNetProject = Item as DotNetProject;
-
- MSBuildProject msproject = new MSBuildProject ();
- newProject = EntityItem.FileName == null || !File.Exists (EntityItem.FileName);
- if (newProject) {
- msproject.DefaultTargets = "Build";
- } else {
- msproject.Load (EntityItem.FileName);
- }
-
- // Global properties
-
- MSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup ();
- if (globalGroup == null) {
- globalGroup = msproject.AddNewPropertyGroup (false);
- }
-
- if (eitem.Configurations.Count > 0) {
- ItemConfiguration conf = eitem.Configurations.FirstOrDefault<ItemConfiguration> (c => c.Name == "Debug");
- if (conf == null) conf = eitem.Configurations [0];
- MSBuildProperty bprop = globalGroup.SetPropertyValue ("Configuration", conf.Name, false);
- bprop.Condition = " '$(Configuration)' == '' ";
-
- string platform = conf.Platform.Length == 0 ? "AnyCPU" : conf.Platform;
- bprop = globalGroup.SetPropertyValue ("Platform", platform, false);
- bprop.Condition = " '$(Platform)' == '' ";
- }
-
- if (TypeGuid == MSBuildProjectService.GenericItemGuid) {
- DataType dt = MSBuildProjectService.DataContext.GetConfigurationDataType (Item.GetType ());
- globalGroup.SetPropertyValue ("ItemType", dt.Name, false);
- }
-
- Item.ExtendedProperties ["ProjectGuid"] = Item.ItemId;
- if (subtypeGuids.Count > 0) {
- string gg = "";
- foreach (string sg in subtypeGuids) {
- if (gg.Length > 0)
- gg += ";";
- gg += sg;
- }
- gg += ";" + TypeGuid;
- Item.ExtendedProperties ["ProjectTypeGuids"] = gg.ToUpper ();
- globalGroup.SetPropertyValue ("ProjectTypeGuids", gg.ToUpper (), true);
- } else {
- Item.ExtendedProperties.Remove ("ProjectTypeGuids");
- globalGroup.RemoveProperty ("ProjectTypeGuids");
- }
-
- Item.ExtendedProperties ["ProductVersion"] = productVersion;
- Item.ExtendedProperties ["SchemaVersion"] = schemaVersion;
-
- // having no ToolsVersion is equivalent to 2.0, roundtrip that correctly
- if (ToolsVersion != "2.0")
- msproject.ToolsVersion = ToolsVersion;
- else if (string.IsNullOrEmpty (msproject.ToolsVersion))
- msproject.ToolsVersion = null;
- else
- msproject.ToolsVersion = "2.0";
-
- // This serialize call will write data to ser.InternalItemProperties and ser.ExternalItemProperties
- ser.Serialize (Item, Item.GetType ());
-
- object langParams = null;
-
- if (dotNetProject != null && dotNetProject.LanguageParameters != null) {
- // Remove all language parameters properties from the data item, since we are going to write them again.
- ClassDataType dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (dotNetProject.LanguageParameters.GetType ());
- foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, dotNetProject.LanguageParameters)) {
- DataNode n = ser.InternalItemProperties.ItemData [prop.Name];
- if (n != null)
- ser.InternalItemProperties.ItemData.Remove (n);
- }
- DataItem ditemComp = (DataItem) ser.Serialize (dotNetProject.LanguageParameters);
- ser.InternalItemProperties.ItemData.AddRange (ditemComp.ItemData);
- langParams = dotNetProject.LanguageParameters;
- }
-
- if (newProject)
- ser.InternalItemProperties.ItemData.Sort (globalConfigOrder);
-
- WritePropertyGroupMetadata (globalGroup, ser.InternalItemProperties.ItemData, ser, Item, langParams);
-
- // Convert debug property
-
- foreach (SolutionItemConfiguration conf in eitem.Configurations) {
- if (newProject && conf is DotNetProjectConfiguration) {
- conf.ExtendedProperties ["ErrorReport"] = "prompt";
- }
- }
-
- // Configurations
-
- if (eitem.Configurations.Count > 0) {
- List<ConfigData> configData = GetConfigData (msproject, true);
-
- var mergeToProjectPropertyValues = new Dictionary<string,MergedPropertyValue> ();
- var mergeToProjectProperties = new HashSet<MergedProperty> (GetMergeToProjectProperties (ser, eitem.Configurations [0]));
- var mergeToProjectPropertyNames = new HashSet<string> (mergeToProjectProperties.Select (p => p.Name));
-
- foreach (SolutionItemConfiguration conf in eitem.Configurations) {
- bool newConf = false;
- ConfigData cdata = FindPropertyGroup (configData, conf);
- if (cdata == null) {
- MSBuildPropertyGroup pg = msproject.AddNewPropertyGroup (true);
- pg.Condition = BuildConfigCondition (conf.Name, conf.Platform);
- cdata = new ConfigData (conf.Name, conf.Platform, pg);
- cdata.IsNew = true;
- configData.Add (cdata);
- newConf = true;
- }
-
- MSBuildPropertyGroup propGroup = cdata.Group;
- cdata.Exists = true;
-
- MSBuildPropertySet baseGroup = GetMergedConfiguration (configData, conf.Name, conf.Platform, propGroup);
-
- // Force the serialization of properties defined in
- // the base group, so that they can be later unmerged
- if (baseGroup != null)
- ForceDefaultValueSerialization (ser, baseGroup, conf);
- DataItem ditem = (DataItem) ser.Serialize (conf);
- ser.SerializationContext.ResetDefaultValueSerialization ();
-
- DotNetProjectConfiguration netConfig = conf as DotNetProjectConfiguration;
-
- if (netConfig != null && netConfig.CompilationParameters != null) {
- // Remove all compilation parameters properties from the data item, since we are going to write them again.
- ClassDataType dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (netConfig.CompilationParameters.GetType ());
- foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, netConfig.CompilationParameters)) {
- DataNode n = ditem.ItemData [prop.Name];
- if (n != null)
- ditem.ItemData.Remove (n);
- }
- if (baseGroup != null)
- ForceDefaultValueSerialization (ser, baseGroup, netConfig.CompilationParameters);
- DataItem ditemComp = (DataItem) ser.Serialize (netConfig.CompilationParameters);
- ser.SerializationContext.ResetDefaultValueSerialization ();
- ditem.ItemData.AddRange (ditemComp.ItemData);
- }
-
- if (newConf)
- ditem.ItemData.Sort (configOrder);
-
- WritePropertyGroupMetadata (propGroup, ditem.ItemData, ser, conf, netConfig != null ? netConfig.CompilationParameters : null);
-
- CollectMergetoprojectProperties (propGroup, mergeToProjectProperties, mergeToProjectPropertyValues);
-
- if (baseGroup != null)
- propGroup.UnMerge (baseGroup, mergeToProjectPropertyNames);
- }
-
- // Move properties with common values from configurations to the main
- // property group
- foreach (KeyValuePair<string,MergedPropertyValue> prop in mergeToProjectPropertyValues)
- globalGroup.SetPropertyValue (prop.Key, prop.Value.XmlValue, prop.Value.PreserveExistingCase, true);
- foreach (string prop in mergeToProjectPropertyNames) {
- if (!mergeToProjectPropertyValues.ContainsKey (prop))
- globalGroup.RemoveProperty (prop);
- }
- foreach (SolutionItemConfiguration conf in eitem.Configurations) {
- MSBuildPropertyGroup propGroup = FindPropertyGroup (configData, conf).Group;
- foreach (string mp in mergeToProjectPropertyValues.Keys)
- propGroup.RemoveProperty (mp);
- }
-
- // Remove groups corresponding to configurations that have been removed
- // or groups which don't have any property and did not already exist
- foreach (ConfigData cd in configData) {
- if ((!cd.Exists && cd.FullySpecified) || (cd.IsNew && !cd.Group.Properties.Any ()))
- msproject.RemoveGroup (cd.Group);
- }
- }
-
- SaveProjectItems (monitor, toolsFormat, ser, msproject);
-
- if (dotNetProject != null) {
- var moniker = dotNetProject.TargetFramework.Id;
- bool supportsMultipleFrameworks = toolsFormat.SupportsMonikers || toolsFormat.SupportedFrameworks.Length > 0;
- var def = dotNetProject.GetDefaultTargetFrameworkForFormat (GetFileFormat (toolsFormat));
-
- // If the format only supports one fx version, or the version is the default, there is no need to store it.
- // However, is there is already a value set, do not remove it.
- if (supportsMultipleFrameworks) {
- SetIfPresentOrNotDefaultValue (globalGroup, "TargetFrameworkVersion", "v" + moniker.Version, "v" + def.Version);
- }
-
- if (toolsFormat.SupportsMonikers) {
- SetIfPresentOrNotDefaultValue (globalGroup, "TargetFrameworkIdentifier", moniker.Identifier, def.Identifier);
- SetIfPresentOrNotDefaultValue (globalGroup, "TargetFrameworkProfile", moniker.Profile, def.Profile);
- }
- }
-
- // Impdate the imports section
-
- List<DotNetProjectImport> currentImports = msproject.Imports.Select (i => new DotNetProjectImport (i.Project)).ToList ();
- List<DotNetProjectImport> imports = new List<DotNetProjectImport> (currentImports);
-
- // If the project is not new, don't add the default project imports,
- // just assume that the current imports are correct
- UpdateImports (imports, dotNetProject, newProject);
- foreach (DotNetProjectImport imp in imports) {
- if (!currentImports.Contains (imp)) {
- MSBuildImport import = msproject.AddNewImport (imp.Name);
- if (imp.HasCondition ())
- import.Condition = imp.Condition;
- currentImports.Add (imp);
- }
- }
- foreach (DotNetProjectImport imp in currentImports) {
- if (!imports.Contains (imp))
- msproject.RemoveImport (imp.Name);
- }
-
- DataItem extendedData = ser.ExternalItemProperties;
- if (extendedData.HasItemData) {
- extendedData.Name = "Properties";
- StringWriter sw = new StringWriter ();
- XmlConfigurationWriter.DefaultWriter.Write (new XmlTextWriter (sw), extendedData);
- msproject.SetProjectExtensions ("MonoDevelop", sw.ToString ());
- } else
- msproject.RemoveProjectExtensions ("MonoDevelop");
-
- SaveToMSBuildProject (monitor, msproject);
-
- return msproject;
- }
-
- internal void SaveProjectItems (IProgressMonitor monitor, MSBuildFileFormat toolsFormat, MSBuildSerializer ser, MSBuildProject msproject, string pathPrefix = null)
- {
- // Remove old items
- Dictionary<string, ItemInfo> oldItems = new Dictionary<string, ItemInfo> ();
- foreach (MSBuildItem item in msproject.GetAllItems ())
- oldItems [item.Name + "<" + item.UnevaluatedInclude + "<" + item.Condition] = new ItemInfo () {
- Item = item
- };
- // Add the new items
- foreach (object ob in ((SolutionEntityItem)Item).Items.Concat (((SolutionEntityItem)Item).WildcardItems).Where (it => !it.Flags.HasFlag (ProjectItemFlags.DontPersist)))
- SaveItem (monitor, toolsFormat, ser, msproject, ob, oldItems, pathPrefix);
- foreach (ItemInfo itemInfo in oldItems.Values) {
- if (!itemInfo.Added)
- msproject.RemoveItem (itemInfo.Item);
- }
- }
-
- protected void SaveToMSBuildProject (IProgressMonitor monitor, MSBuildProject msproject)
- {
- foreach (var ext in GetMSBuildExtensions ())
- ext.SaveProject (monitor, EntityItem, msproject);
- }
-
- void SetIfPresentOrNotDefaultValue (MSBuildPropertySet propGroup, string name, string value, string defaultValue, bool isXml = false)
- {
- bool hasDefaultValue = string.IsNullOrEmpty (value) || value == defaultValue;
- var prop = propGroup.GetProperty (name);
- if (prop != null) {
- //if the value is default or empty, only remove the element if it was not already the default or empty
- //to avoid unnecessary project file churn
- if (hasDefaultValue) {
- var existing = prop.GetValue (isXml);
- bool alreadyHadDefaultValue = string.IsNullOrEmpty (existing) || existing == defaultValue;
- if (!alreadyHadDefaultValue)
- propGroup.RemoveProperty (name);
- } else {
- prop.SetValue (value, isXml);
- }
- } else if (!hasDefaultValue) {
- propGroup.SetPropertyValue (name, value, false, isXml);
- }
- }
-
- void ForceDefaultValueSerialization (MSBuildSerializer ser, MSBuildPropertySet baseGroup, object ob)
- {
- ClassDataType dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (ob.GetType());
- foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, ob)) {
- if (baseGroup.GetProperty (prop.Name) != null)
- ser.SerializationContext.ForceDefaultValueSerialization (prop);
- }
- }
-
- void CollectMergetoprojectProperties (MSBuildPropertyGroup pgroup, HashSet<MergedProperty> properties, Dictionary<string,MergedPropertyValue> mergeToProjectProperties)
- {
- // This method checks every property in pgroup which has the MergeToProject flag.
- // If the value of this property is the same as the one stored in mergeToProjectProperties
- // it means that the property can be merged to the main project property group (so far).
-
- foreach (var pinfo in new List<MergedProperty> (properties)) {
- MSBuildProperty prop = pgroup.GetProperty (pinfo.Name);
-
- MergedPropertyValue mvalue;
- if (!mergeToProjectProperties.TryGetValue (pinfo.Name, out mvalue)) {
- if (prop != null) {
- // This is the first time the value is checked. Just assign it.
- mergeToProjectProperties.Add (pinfo.Name, new MergedPropertyValue (prop.GetValue (true), pinfo.PreserveExistingCase));
- continue;
- }
- // If there is no value, it can't be merged
- }
- else if (prop != null && string.Equals (prop.GetValue (true), mvalue.XmlValue, StringComparison.OrdinalIgnoreCase))
- // Same value. It can be merged.
- continue;
-
- // The property can't be merged because different configurations have different
- // values for it. Remove it from the list.
- properties.Remove (pinfo);
- mergeToProjectProperties.Remove (pinfo.Name);
- }
- }
-
- struct MergedPropertyValue
- {
- public readonly string XmlValue;
- public readonly bool PreserveExistingCase;
-
- public MergedPropertyValue (string xmlValue, bool preserveExistingCase)
- {
- this.XmlValue = xmlValue;
- this.PreserveExistingCase = preserveExistingCase;
- }
- }
-
- void SaveItem (IProgressMonitor monitor, MSBuildFileFormat fmt, MSBuildSerializer ser, MSBuildProject msproject, object ob, Dictionary<string,ItemInfo> oldItems, string pathPrefix = null)
- {
- if (ob is ProjectReference) {
- SaveReference (monitor, fmt, ser, msproject, (ProjectReference) ob, oldItems);
- }
- else if (ob is ProjectFile) {
- SaveProjectFile (ser, msproject, (ProjectFile) ob, oldItems, pathPrefix);
- }
- else {
- string itemName;
- if (ob is UnknownProjectItem) {
- var ui = (UnknownProjectItem)ob;
- itemName = ui.ItemName;
- var buildItem = AddOrGetBuildItem (msproject, oldItems, itemName, ui.Include, ui.Condition);
- WriteBuildItemMetadata (ser, buildItem, ob, oldItems);
- }
- else {
- DataType dt = ser.DataContext.GetConfigurationDataType (ob.GetType ());
- var buildItem = msproject.AddNewItem (dt.Name, "");
- WriteBuildItemMetadata (ser, buildItem, ob, oldItems);
- }
- }
- }
-
- void SaveProjectFile (MSBuildSerializer ser, MSBuildProject msproject, ProjectFile file, Dictionary<string,ItemInfo> oldItems, string pathPrefix = null)
- {
- if (file.IsOriginatedFromWildcard) return;
-
- string itemName = (file.Subtype == Subtype.Directory)? "Folder" : file.BuildAction;
-
- string path = pathPrefix + MSBuildProjectService.ToMSBuildPath (Item.ItemDirectory, file.FilePath);
- if (path.Length == 0)
- return;
-
- //directory paths must end with '/'
- if ((file.Subtype == Subtype.Directory) && path[path.Length-1] != '\\')
- path = path + "\\";
-
- MSBuildItem buildItem = AddOrGetBuildItem (msproject, oldItems, itemName, path, file.Condition);
- WriteBuildItemMetadata (ser, buildItem, file, oldItems);
-
- if (!string.IsNullOrEmpty (file.DependsOn))
- buildItem.SetMetadata ("DependentUpon", MSBuildProjectService.ToMSBuildPath (Path.GetDirectoryName (file.FilePath), file.DependsOn));
- else
- buildItem.UnsetMetadata ("DependentUpon");
-
- if (!string.IsNullOrEmpty (file.ContentType))
- buildItem.SetMetadata ("SubType", file.ContentType);
-
- if (!string.IsNullOrEmpty (file.Generator))
- buildItem.SetMetadata ("Generator", file.Generator);
- else
- buildItem.UnsetMetadata ("Generator");
-
- if (!string.IsNullOrEmpty (file.CustomToolNamespace))
- buildItem.SetMetadata ("CustomToolNamespace", file.CustomToolNamespace);
- else
- buildItem.UnsetMetadata ("CustomToolNamespace");
-
- if (!string.IsNullOrEmpty (file.LastGenOutput))
- buildItem.SetMetadata ("LastGenOutput", file.LastGenOutput);
- else
- buildItem.UnsetMetadata ("LastGenOutput");
-
- if (!string.IsNullOrEmpty (file.Link))
- buildItem.SetMetadata ("Link", MSBuildProjectService.ToMSBuildPathRelative (Item.ItemDirectory, file.Link));
- else
- buildItem.UnsetMetadata ("Link");
-
- buildItem.Condition = file.Condition;
-
- if (file.CopyToOutputDirectory == FileCopyMode.None) {
- buildItem.UnsetMetadata ("CopyToOutputDirectory");
- } else {
- buildItem.SetMetadata ("CopyToOutputDirectory", file.CopyToOutputDirectory.ToString ());
- }
-
- if (!file.Visible) {
- buildItem.SetMetadata ("Visible", "False");
- } else {
- buildItem.UnsetMetadata ("Visible");
- }
-
- var resId = file.ResourceId;
-
- //For EmbeddedResource, emit LogicalName only when it does not match the default Id
- if (file.BuildAction == BuildAction.EmbeddedResource && GetDefaultResourceId (file) == resId)
- resId = null;
-
- if (!string.IsNullOrEmpty (resId)) {
- buildItem.SetMetadata ("LogicalName", resId);
- } else {
- buildItem.UnsetMetadata ("LogicalName");
- }
- }
-
- void SaveReference (IProgressMonitor monitor, MSBuildFileFormat fmt, MSBuildSerializer ser, MSBuildProject msproject, ProjectReference pref, Dictionary<string,ItemInfo> oldItems)
- {
- MSBuildItem buildItem;
- if (pref.ReferenceType == ReferenceType.Assembly) {
- string asm = null;
- string hintPath = null;
- if (pref.ExtendedProperties.Contains ("_OriginalMSBuildReferenceInclude")) {
- asm = (string) pref.ExtendedProperties ["_OriginalMSBuildReferenceInclude"];
- hintPath = (string) pref.ExtendedProperties ["_OriginalMSBuildReferenceHintPath"];
- }
- else {
- if (File.Exists (pref.HintPath)) {
- try {
- var aname = AssemblyName.GetAssemblyName (pref.HintPath);
- if (pref.SpecificVersion) {
- asm = aname.FullName;
- } else {
- asm = aname.Name;
- }
- } catch (Exception ex) {
- string msg = string.Format ("Could not get full name for assembly '{0}'.", pref.Reference);
- monitor.ReportWarning (msg);
- LoggingService.LogError (msg, ex);
- }
- }
- string basePath = Item.ItemDirectory;
- if (pref.ExtendedProperties.Contains ("_OriginalMSBuildReferenceIsAbsolute"))
- basePath = null;
- hintPath = MSBuildProjectService.ToMSBuildPath (basePath, pref.HintPath);
- }
- if (asm == null)
- asm = Path.GetFileNameWithoutExtension (pref.Reference);
-
- buildItem = AddOrGetBuildItem (msproject, oldItems, "Reference", asm, pref.Condition);
-
- if (!pref.SpecificVersion && ReferenceStringHasVersion (asm)) {
- buildItem.SetMetadata ("SpecificVersion", "False");
- } else {
- buildItem.UnsetMetadata ("SpecificVersion");
- }
-
- buildItem.SetMetadata ("HintPath", hintPath);
- }
- else if (pref.ReferenceType == ReferenceType.Package) {
- string include = pref.StoredReference;
- SystemPackage pkg = pref.Package;
- if (pkg != null && pkg.IsFrameworkPackage) {
- int i = include.IndexOf (',');
- if (i != -1)
- include = include.Substring (0, i).Trim ();
- }
- buildItem = AddOrGetBuildItem (msproject, oldItems, "Reference", include, pref.Condition);
- if (!pref.SpecificVersion && ReferenceStringHasVersion (include))
- buildItem.SetMetadata ("SpecificVersion", "False");
- else
- buildItem.UnsetMetadata ("SpecificVersion");
-
- //RequiredTargetFramework is undocumented, maybe only a hint for VS. Only seems to be used for .NETFramework
- var dnp = pref.OwnerProject as DotNetProject;
- IList supportedFrameworks = fmt.SupportedFrameworks;
- if (supportedFrameworks != null && dnp != null && pkg != null
- && dnp.TargetFramework.Id.Identifier == TargetFrameworkMoniker.ID_NET_FRAMEWORK
- && pkg.IsFrameworkPackage && supportedFrameworks.Contains (pkg.TargetFramework)
- && pkg.TargetFramework.Version != "2.0" && supportedFrameworks.Count > 1)
- {
- TargetFramework fx = Runtime.SystemAssemblyService.GetTargetFramework (pkg.TargetFramework);
- buildItem.SetMetadata ("RequiredTargetFramework", fx.Id.Version);
- } else {
- buildItem.UnsetMetadata ("RequiredTargetFramework");
- }
-
- string hintPath = (string) pref.ExtendedProperties ["_OriginalMSBuildReferenceHintPath"];
- if (hintPath != null)
- buildItem.SetMetadata ("HintPath", hintPath);
- else
- buildItem.UnsetMetadata ("HintPath");
- }
- else if (pref.ReferenceType == ReferenceType.Project) {
- Project refProj = Item.ParentSolution.FindProjectByName (pref.Reference);
- if (refProj != null) {
- buildItem = AddOrGetBuildItem (msproject, oldItems, "ProjectReference", MSBuildProjectService.ToMSBuildPath (Item.ItemDirectory, refProj.FileName), pref.Condition);
- MSBuildProjectHandler handler = refProj.ItemHandler as MSBuildProjectHandler;
- if (handler != null)
- buildItem.SetMetadata ("Project", handler.Item.ItemId);
- else
- buildItem.UnsetMetadata ("Project");
- buildItem.SetMetadata ("Name", refProj.Name);
- } else {
- monitor.ReportWarning (GettextCatalog.GetString ("Reference to unknown project '{0}' ignored.", pref.Reference));
- return;
- }
- }
- else {
- // Custom
- DataType dt = ser.DataContext.GetConfigurationDataType (pref.GetType ());
- buildItem = AddOrGetBuildItem (msproject, oldItems, dt.Name, pref.Reference, pref.Condition);
- }
-
- if (pref.LocalCopy != pref.DefaultLocalCopy)
- buildItem.SetMetadata ("Private", pref.LocalCopy);
- else
- buildItem.UnsetMetadata ("Private");
-
- WriteBuildItemMetadata (ser, buildItem, pref, oldItems);
- buildItem.Condition = pref.Condition;
- }
-
- void UpdateImports (List<DotNetProjectImport> imports, DotNetProject project, bool addItemTypeImports)
- {
- if (targetImports != null && addItemTypeImports) {
- AddMissingImports (imports, targetImports);
- }
-
- List <string> updatedImports = imports.Select (import => import.Name).ToList ();
- foreach (IMSBuildImportProvider ip in AddinManager.GetExtensionObjects ("/MonoDevelop/ProjectModel/MSBuildImportProviders")) {
- ip.UpdateImports (EntityItem, updatedImports);
- }
-
- UpdateImports (imports, updatedImports);
-
- if (project != null) {
- AddMissingImports (imports, project.ImportsAdded);
- RemoveImports (imports, project.ImportsRemoved);
- project.ImportsSaved ();
- }
- }
-
- void AddMissingImports (List<DotNetProjectImport> existingImports, IEnumerable<string> newImports)
- {
- AddMissingImports (existingImports, newImports.Select (import => new DotNetProjectImport (import)));
- }
-
- void AddMissingImports (List<DotNetProjectImport> existingImports, IEnumerable<DotNetProjectImport> newImports)
- {
- foreach (DotNetProjectImport imp in newImports)
- if (!existingImports.Contains (imp))
- existingImports.Add (imp);
- }
-
- void UpdateImports (List<DotNetProjectImport> existingImports, List<string> updatedImports)
- {
- RemoveMissingImports (existingImports, updatedImports);
- AddMissingImports (existingImports, updatedImports);
- }
-
- void RemoveMissingImports (List<DotNetProjectImport> existingImports, List<string> updatedImports)
- {
- List <DotNetProjectImport> importsToRemove = existingImports.Where (import => !updatedImports.Contains (import.Name)).ToList ();
- RemoveImports (existingImports, importsToRemove);
- }
-
- void RemoveImports (List<DotNetProjectImport> existingImports, IEnumerable<DotNetProjectImport> importsToRemove)
- {
- foreach (DotNetProjectImport imp in importsToRemove)
- existingImports.Remove (imp);
- }
-
- IEnumerable<MSBuildExtension> GetMSBuildExtensions ()
- {
- foreach (var e in AddinManager.GetExtensionObjects<MSBuildExtension> ("/MonoDevelop/ProjectModel/MSBuildExtensions")) {
- e.Handler = this;
- yield return e;
- }
- }
-
- void ReadBuildItemMetadata (DataSerializer ser, MSBuildItem buildItem, object dataItem, Type extendedType)
- {
- DataItem ditem = new DataItem ();
- foreach (ItemProperty prop in ser.GetProperties (dataItem)) {
- string name = ToMsbuildItemName (prop.Name);
- if (name == "Include")
- ditem.ItemData.Add (new DataValue ("Include", buildItem.Include));
- else if (buildItem.HasMetadata (name)) {
- string data = buildItem.GetMetadata (name, !prop.DataType.IsSimpleType);
- ditem.ItemData.Add (GetDataNode (prop, data));
- }
- }
- ConvertFromMsbuildFormat (ditem);
- ser.Deserialize (dataItem, ditem);
- }
-
- void WriteBuildItemMetadata (DataSerializer ser, MSBuildItem buildItem, object dataItem, Dictionary<string,ItemInfo> oldItems)
- {
- var notWrittenProps = new HashSet<string> ();
- foreach (ItemProperty prop in ser.GetProperties (dataItem))
- notWrittenProps.Add (prop.Name);
-
- DataItem ditem = (DataItem) ser.Serialize (dataItem, dataItem.GetType ());
- if (ditem.HasItemData) {
- foreach (DataNode node in ditem.ItemData) {
- notWrittenProps.Remove (node.Name);
- if (node.Name == "Include" && node is DataValue)
- buildItem.Include = ((DataValue) node).Value;
- else {
- ConvertToMsbuildFormat (node);
- buildItem.SetMetadata (node.Name, GetXmlString (node), node is DataItem);
- }
- }
- }
- foreach (string prop in notWrittenProps)
- buildItem.UnsetMetadata (prop);
- }
-
- MSBuildItem AddOrGetBuildItem (MSBuildProject msproject, Dictionary<string,ItemInfo> oldItems, string name, string include, string condition)
- {
- ItemInfo itemInfo;
- string key = name + "<" + include + "<" + condition;
- if (oldItems.TryGetValue (key, out itemInfo)) {
- if (!itemInfo.Added) {
- itemInfo.Added = true;
- oldItems [key] = itemInfo;
- }
- return itemInfo.Item;
- } else {
- return msproject.AddNewItem (name, include);
- }
- }
-
- DataItem ReadPropertyGroupMetadata (DataSerializer ser, MSBuildPropertySet propGroup, object dataItem)
- {
- DataItem ditem = new DataItem ();
-
- foreach (MSBuildProperty bprop in propGroup.Properties) {
- DataNode node = null;
- foreach (XmlNode xnode in bprop.Element.ChildNodes) {
- if (xnode is XmlElement) {
- node = XmlConfigurationReader.DefaultReader.Read ((XmlElement)xnode);
- break;
- }
- }
- if (node == null) {
- node = new DataValue (bprop.Name, bprop.GetValue (false));
- }
-
- ConvertFromMsbuildFormat (node);
- ditem.ItemData.Add (node);
- }
-
- return ditem;
- }
-
- void WritePropertyGroupMetadata (MSBuildPropertySet propGroup, DataCollection itemData, MSBuildSerializer ser, params object[] itemsToReplace)
- {
- var notWrittenProps = new HashSet<string> ();
-
- foreach (object ob in itemsToReplace) {
- if (ob == null)
- continue;
- ClassDataType dt = (ClassDataType) ser.DataContext.GetConfigurationDataType (ob.GetType ());
- foreach (ItemProperty prop in dt.GetProperties (ser.SerializationContext, ob))
- notWrittenProps.Add (prop.Name);
- }
-
- foreach (DataNode node in itemData) {
- notWrittenProps.Remove (node.Name);
- ConvertToMsbuildFormat (node);
-
- // In the other msbuild contexts (metadata, solution properties, etc) we TitleCase by default, so the node.Value is TitleCase.
- // However, for property value, we lowercase by default and preserve existing case to reduce noise on VS-created files.
- var boolNode = node as MSBuildBoolDataValue;
- string value;
- bool preserveExistingCase;
- if (boolNode != null) {
- value = boolNode.RawValue? "true" : "false";
- preserveExistingCase = true;
- } else {
- value = GetXmlString (node);
- preserveExistingCase = false;
- }
-
- propGroup.SetPropertyValue (node.Name, value, preserveExistingCase, node is DataItem);
- }
- foreach (string prop in notWrittenProps)
- propGroup.RemoveProperty (prop);
- }
-
- string ToMsbuildItemName (string name)
- {
- return name.Replace ('.', '-');
- }
-
- void ConvertToMsbuildFormat (DataNode node)
- {
- ReplaceChar (node, true, '.', '-');
- }
-
- void ConvertFromMsbuildFormat (DataNode node)
- {
- ReplaceChar (node, true, '-', '.');
- }
-
- void ReplaceChar (DataNode node, bool force, char oldChar, char newChar)
- {
- DataItem it = node as DataItem;
- if ((force || it != null) && node.Name != null)
- node.Name = node.Name.Replace (oldChar, newChar);
- if (it != null) {
- foreach (DataNode cnode in it.ItemData)
- ReplaceChar (cnode, !it.UniqueNames, oldChar, newChar);
- }
- }
-
- List<ConfigData> GetConfigData (MSBuildProject msproject, bool includeGlobalGroups)
- {
- List<ConfigData> configData = new List<ConfigData> ();
- foreach (MSBuildPropertyGroup cgrp in msproject.PropertyGroups) {
- string conf, platform;
- if (ParseConfigCondition (cgrp.Condition, out conf, out platform) || includeGlobalGroups)
- configData.Add (new ConfigData (conf, platform, cgrp));
- }
- return configData;
- }
-
- ConfigData FindPropertyGroup (List<ConfigData> configData, SolutionItemConfiguration config)
- {
- foreach (ConfigData data in configData) {
- if (data.Config == config.Name && data.Platform == config.Platform)
- return data;
- }
- return null;
- }
-
- ProjectFile ReadProjectFile (DataSerializer ser, Project project, MSBuildItem buildItem, Type type)
- {
- string path = MSBuildProjectService.FromMSBuildPath (project.ItemDirectory, buildItem.Include);
- ProjectFile file = (ProjectFile) Activator.CreateInstance (type);
- file.Name = path;
- file.BuildAction = buildItem.Name;
-
- ReadBuildItemMetadata (ser, buildItem, file, type);
-
- string dependentFile = buildItem.GetMetadata ("DependentUpon");
- if (!string.IsNullOrEmpty (dependentFile)) {
- dependentFile = MSBuildProjectService.FromMSBuildPath (Path.GetDirectoryName (path), dependentFile);
- file.DependsOn = dependentFile;
- }
-
- string copyToOutputDirectory = buildItem.GetMetadata ("CopyToOutputDirectory");
- if (!string.IsNullOrEmpty (copyToOutputDirectory)) {
- switch (copyToOutputDirectory) {
- case "None": break;
- case "Always": file.CopyToOutputDirectory = FileCopyMode.Always; break;
- case "PreserveNewest": file.CopyToOutputDirectory = FileCopyMode.PreserveNewest; break;
- default:
- MonoDevelop.Core.LoggingService.LogWarning (
- "Unrecognised value {0} for CopyToOutputDirectory MSBuild property",
- copyToOutputDirectory);
- break;
- }
- }
-
- if (buildItem.GetMetadataIsFalse ("Visible"))
- file.Visible = false;
-
-
- string resourceId = buildItem.GetMetadata ("LogicalName");
- if (!string.IsNullOrEmpty (resourceId))
- file.ResourceId = resourceId;
-
- string contentType = buildItem.GetMetadata ("SubType");
- if (!string.IsNullOrEmpty (contentType))
- file.ContentType = contentType;
-
- string generator = buildItem.GetMetadata ("Generator");
- if (!string.IsNullOrEmpty (generator))
- file.Generator = generator;
-
- string customToolNamespace = buildItem.GetMetadata ("CustomToolNamespace");
- if (!string.IsNullOrEmpty (customToolNamespace))
- file.CustomToolNamespace = customToolNamespace;
-
- string lastGenOutput = buildItem.GetMetadata ("LastGenOutput");
- if (!string.IsNullOrEmpty (lastGenOutput))
- file.LastGenOutput = lastGenOutput;
-
- string link = buildItem.GetMetadata ("Link");
- if (!string.IsNullOrEmpty (link)) {
- if (!Platform.IsWindows)
- link = MSBuildProjectService.UnescapePath (link);
- file.Link = link;
- }
-
- file.Condition = buildItem.Condition;
- return file;
- }
-
- bool ParseConfigCondition (string cond, out string config, out string platform)
- {
- config = platform = Unspecified;
- int i = cond.IndexOf ("==");
- if (i == -1)
- return false;
- if (cond.Substring (0, i).Trim () == "'$(Configuration)|$(Platform)'") {
- cond = cond.Substring (i+2).Trim (' ','\'');
- i = cond.IndexOf ('|');
- if (i != -1) {
- config = cond.Substring (0, i);
- platform = cond.Substring (i+1);
- } else {
- // Invalid configuration
- return false;
- }
- if (platform == "AnyCPU")
- platform = string.Empty;
- return true;
- }
- else if (cond.Substring (0, i).Trim () == "'$(Configuration)'") {
- config = cond.Substring (i+2).Trim (' ','\'');
- platform = Unspecified;
- return true;
- }
- else if (cond.Substring (0, i).Trim () == "'$(Platform)'") {
- config = Unspecified;
- platform = cond.Substring (i+2).Trim (' ','\'');
- if (platform == "AnyCPU")
- platform = string.Empty;
- return true;
- }
- return false;
- }
-
- string BuildConfigCondition (string config, string platform)
- {
- if (platform.Length == 0)
- platform = "AnyCPU";
- return " '$(Configuration)|$(Platform)' == '" + config + "|" + platform + "' ";
- }
-
- bool IsMergeToProjectProperty (ItemProperty prop)
- {
- foreach (object at in prop.CustomAttributes) {
- if (at is MergeToProjectAttribute)
- return true;
- }
- return false;
- }
-
- string GetXmlString (DataNode node)
- {
- if (node is DataValue)
- return ((DataValue)node).Value;
- else {
- StringWriter sw = new StringWriter ();
- XmlTextWriter xw = new XmlTextWriter (sw);
- XmlConfigurationWriter.DefaultWriter.Write (xw, node);
- return sw.ToString ();
- }
- }
-
- DataNode GetDataNode (ItemProperty prop, string xmlString)
- {
- if (prop.DataType.IsSimpleType)
- return new DataValue (prop.Name, xmlString);
- else {
- StringReader sr = new StringReader (xmlString);
- return XmlConfigurationReader.DefaultReader.Read (new XmlTextReader (sr));
- }
- }
-
- internal virtual MSBuildSerializer CreateSerializer ()
- {
- return new MSBuildSerializer (EntityItem.FileName);
- }
-
- static readonly MSBuildElementOrder globalConfigOrder = new MSBuildElementOrder (
- "Configuration","Platform","ProductVersion","SchemaVersion","ProjectGuid", "OutputType",
- "AppDesignerFolder","RootNamespace","AssemblyName","StartupObject"
- );
- static readonly MSBuildElementOrder configOrder = new MSBuildElementOrder (
- "DebugSymbols","DebugType","Optimize","OutputPath","DefineConstants","ErrorReport","WarningLevel",
- "TreatWarningsAsErrors","DocumentationFile"
- );
-
- // Those are properties which are dynamically set by this file format
-
- internal static readonly ItemMember[] ExtendedMSBuildProperties = new ItemMember [] {
- new ItemMember (typeof(SolutionEntityItem), "ProductVersion"),
- new ItemMember (typeof(SolutionEntityItem), "SchemaVersion"),
- new ItemMember (typeof(SolutionEntityItem), "ProjectGuid"),
- new ItemMember (typeof(DotNetProjectConfiguration), "ErrorReport"),
- new ItemMember (typeof(DotNetProjectConfiguration), "TargetFrameworkVersion", new object[] { new MergeToProjectAttribute () }),
- new ItemMember (typeof(ProjectReference), "RequiredTargetFramework"),
- new ItemMember (typeof(Project), "InternalTargetFrameworkVersion", true),
- };
-
- // Items generated by VS but which MD is not using and should be ignored
-
- internal static readonly IList<string> UnsupportedItems = new string[] {
- "BootstrapperFile", "AppDesigner", "WebReferences", "WebReferenceUrl", "Service",
- "ProjectReference", "Reference", // Reference elements are included here because they are special-cased for DotNetProject, and they are unsupported in other types of projects
- "InternalsVisibleTo",
- "InternalsVisibleToTest"
- };
- }
-
class MSBuildSerializer: DataSerializer
{
public DataItem InternalItemProperties = new DataItem ();
@@ -2061,8 +67,8 @@ namespace MonoDevelop.Projects.Formats.MSBuild
if (prop.Name == "References" || prop.Name == "LanguageParameters")
return false;
}
- if (instance is SolutionEntityItem) {
- if (prop.IsExtendedProperty (typeof(SolutionEntityItem)))
+ if (instance is SolutionItem) {
+ if (prop.IsExtendedProperty (typeof(SolutionItem)))
return true;
return prop.Name != "name" && prop.Name != "Configurations";
}
@@ -2086,7 +92,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
internal protected override DataNode OnSerializeProperty (ItemProperty prop, SerializationContext serCtx, object instance, object value)
{
DataNode data = base.OnSerializeProperty (prop, serCtx, instance, value);
- if (instance is SolutionEntityItem && data != null) {
+ if (instance is SolutionItem && data != null) {
if (prop.IsExternal)
ExternalItemProperties.ItemData.Add (data);
else
@@ -2096,22 +102,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
}
- class UnknownSolutionItemTypeException : InvalidOperationException
- {
- public UnknownSolutionItemTypeException ()
- : base ("Unknown solution item type")
- {
- }
-
- public UnknownSolutionItemTypeException (string name)
- : base ("Unknown solution item type: " + name)
- {
- this.TypeName = name;
- }
-
- public string TypeName { get; private set; }
- }
-
class MSBuildElementOrder: Dictionary<string, int>
{
public MSBuildElementOrder (params string[] elements)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs
index ac766786b6..3059abfd4e 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs
@@ -41,12 +41,14 @@ using MonoDevelop.Core;
using MonoDevelop.Core.Assemblies;
using Cecil = Mono.Cecil;
using System.Threading;
+using System.Threading.Tasks;
+using System.Xml;
namespace MonoDevelop.Projects.Formats.MSBuild
{
public static class MSBuildProjectService
{
- const string ItemTypesExtensionPath = "/MonoDevelop/ProjectModel/MSBuildItemTypes";
+ internal const string ItemTypesExtensionPath = "/MonoDevelop/ProjectModel/MSBuildItemTypes";
public const string GenericItemGuid = "{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}";
public const string FolderTypeGuid = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}";
@@ -58,7 +60,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
static IMSBuildGlobalPropertyProvider[] globalPropertyProviders;
static Dictionary<string,RemoteBuildEngine> builders = new Dictionary<string, RemoteBuildEngine> ();
- static GenericItemTypeNode genericItemTypeNode = new GenericItemTypeNode ();
+ static Dictionary<string,Type> genericProjectTypes = new Dictionary<string, Type> ();
internal static bool ShutDown { get; private set; }
@@ -67,13 +69,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild
if (dataContext == null) {
dataContext = new MSBuildDataContext ();
Services.ProjectService.InitializeDataContext (dataContext);
- foreach (ItemMember prop in MSBuildProjectHandler.ExtendedMSBuildProperties) {
- ItemProperty iprop = new ItemProperty (prop.Name, prop.Type);
- iprop.IsExternal = prop.IsExternal;
- if (prop.CustomAttributes != null)
- iprop.CustomAttributes = prop.CustomAttributes;
- dataContext.RegisterProperty (prop.DeclaringType, iprop);
- }
}
return dataContext;
}
@@ -88,10 +83,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
PropertyService.PropertyChanged += HandlePropertyChanged;
DefaultMSBuildVerbosity = PropertyService.Get ("MonoDevelop.Ide.MSBuildVerbosity", MSBuildVerbosity.Normal);
- Runtime.ShuttingDown += delegate {
- ShutDown = true;
- CleanProjectBuilders ();
- };
+ Runtime.ShuttingDown += (sender, e) => ShutDown = true;
const string gppPath = "/MonoDevelop/ProjectModel/MSBuildGlobalPropertyProviders";
globalPropertyProviders = AddinManager.GetExtensionObjects<IMSBuildGlobalPropertyProvider> (gppPath);
@@ -118,84 +110,184 @@ namespace MonoDevelop.Projects.Formats.MSBuild
internal static MSBuildVerbosity DefaultMSBuildVerbosity { get; private set; }
- public static SolutionEntityItem LoadItem (IProgressMonitor monitor, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid)
+ public async static Task<SolutionItem> LoadItem (ProgressMonitor monitor, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid)
{
- foreach (ItemTypeNode node in GetItemTypeNodes ()) {
+ foreach (SolutionItemTypeNode node in GetItemTypeNodes ()) {
if (node.CanHandleFile (fileName, typeGuid))
- return node.LoadSolutionItem (monitor, fileName, expectedFormat, itemGuid);
+ return await LoadProjectAsync (monitor, fileName, expectedFormat, typeGuid, null, node);
}
- if (string.IsNullOrEmpty (typeGuid) && IsProjectSubtypeFile (fileName)) {
- typeGuid = LoadProjectTypeGuids (fileName);
- foreach (ItemTypeNode node in GetItemTypeNodes ()) {
- if (node.CanHandleFile (fileName, typeGuid))
- return node.LoadSolutionItem (monitor, fileName, expectedFormat, itemGuid);
- }
- }
-
// If it is a known unsupported project, load it as UnknownProject
var projectInfo = MSBuildProjectService.GetUnknownProjectTypeInfo (typeGuid != null ? new [] { typeGuid } : new string[0], fileName);
if (projectInfo != null && projectInfo.LoadFiles) {
if (typeGuid == null)
typeGuid = projectInfo.Guid;
- var h = new MSBuildProjectHandler (typeGuid, "", itemGuid);
- h.SetUnsupportedType (projectInfo);
- return h.Load (monitor, fileName, expectedFormat, "", null);
+ var p = (UnknownProject) await LoadProjectAsync (monitor, fileName, expectedFormat, "", typeof(UnknownProject), null);
+ p.UnsupportedProjectMessage = projectInfo.GetInstructions ();
+ return p;
}
-
return null;
}
-
- internal static IResourceHandler GetResourceHandlerForItem (DotNetProject project)
+
+ internal static async Task<SolutionItem> LoadProjectAsync (ProgressMonitor monitor, string fileName, MSBuildFileFormat format, string typeGuid, Type itemType, SolutionItemTypeNode node)
{
- foreach (ItemTypeNode node in GetItemTypeNodes ()) {
- DotNetProjectNode pNode = node as DotNetProjectNode;
- if (pNode != null && pNode.CanHandleItem (project))
- return pNode.GetResourceHandler ();
+ try {
+ ProjectExtensionUtil.BeginLoadOperation ();
+ var item = await CreateSolutionItem (monitor, fileName, typeGuid, itemType, node);
+ item.TypeGuid = typeGuid ?? node.Guid;
+ await item.LoadAsync (monitor, fileName, format);
+ return item;
+ } finally {
+ ProjectExtensionUtil.EndLoadOperation ();
}
- return new MSBuildResourceHandler ();
}
-
- internal static MSBuildHandler GetItemHandler (SolutionEntityItem item)
+
+ // All of the last 4 parameters are optional, but at least one must be provided.
+ static async Task<SolutionItem> CreateSolutionItem (ProgressMonitor monitor, string fileName, string typeGuid, Type itemClass, SolutionItemTypeNode node)
{
- MSBuildHandler handler = item.ItemHandler as MSBuildHandler;
- if (handler != null)
- return handler;
- else
- throw new InvalidOperationException ("Not an MSBuild project");
+ if (itemClass != null)
+ return (SolutionItem)Activator.CreateInstance (itemClass);
+
+ return await node.CreateSolutionItem (monitor, fileName, typeGuid ?? node.Guid);
}
-
- internal static void SetId (SolutionItem item, string id)
+
+ internal static bool CanCreateSolutionItem (string type, ProjectCreateInformation info, System.Xml.XmlElement projectOptions)
{
- MSBuildHandler handler = item.ItemHandler as MSBuildHandler;
- if (handler != null)
- handler.ItemId = id;
- else
- throw new InvalidOperationException ("Not an MSBuild project");
+ foreach (var node in GetItemTypeNodes ()) {
+ if (node.CanCreateSolutionItem (type, info, projectOptions))
+ return true;
+ }
+ return false;
}
-
- internal static void InitializeItemHandler (SolutionItem item)
- {
- SolutionEntityItem eitem = item as SolutionEntityItem;
- if (eitem != null) {
- foreach (ItemTypeNode node in GetItemTypeNodes ()) {
- if (node.CanHandleItem (eitem)) {
- node.InitializeHandler (eitem);
- foreach (DotNetProjectSubtypeNode snode in GetItemSubtypeNodes ()) {
- if (snode.CanHandleItem (eitem))
- snode.InitializeHandler (eitem);
- }
- return;
+
+ internal static SolutionItem CreateSolutionItem (string typeGuid)
+ {
+ foreach (var node in GetItemTypeNodes ()) {
+ if (node.Guid.Equals (typeGuid, StringComparison.OrdinalIgnoreCase)) {
+ return node.CreateSolutionItem (new ProgressMonitor (), null, typeGuid).Result;
+ }
+ }
+ throw new InvalidOperationException ("Unknown project type: " + typeGuid);
+ }
+
+ internal static SolutionItem CreateSolutionItem (string type, ProjectCreateInformation info, System.Xml.XmlElement projectOptions)
+ {
+ foreach (var node in GetItemTypeNodes ()) {
+ if (node.CanCreateSolutionItem (type, info, projectOptions))
+ return node.CreateSolutionItem (type, info, projectOptions);
+ }
+ throw new InvalidOperationException ("Unknown project type: " + type);
+ }
+
+/* internal static bool CanMigrateFlavor (string[] guids)
+ {
+
+ }
+
+ internal static async Task<bool> MigrateFlavor (IProgressMonitor monitor, string fileName, string typeGuid, MSBuildProjectNode node, MSBuildProject p)
+ {
+ var language = GetLanguageFromGuid (typeGuid);
+
+ if (MigrateProject (monitor, node, p, fileName, language)) {
+ p.Save (fileName);
+ return true;
+ }
+
+ return false;
+ }
+
+ static async Task<bool> MigrateProject (IProgressMonitor monitor, MSBuildProjectNode st, MSBuildProject p, string fileName, string language)
+ {
+ var projectLoadMonitor = monitor as IProjectLoadProgressMonitor;
+ if (projectLoadMonitor == null) {
+ // projectLoadMonitor will be null when running through md-tool, but
+ // this is not fatal if migration is not required, so just ignore it. --abock
+ if (!st.IsMigrationRequired)
+ return false;
+
+ LoggingService.LogError (Environment.StackTrace);
+ monitor.ReportError ("Could not open unmigrated project and no migrator was supplied", null);
+ throw new Exception ("Could not open unmigrated project and no migrator was supplied");
+ }
+
+ var migrationType = st.MigrationHandler.CanPromptForMigration
+ ? st.MigrationHandler.PromptForMigration (projectLoadMonitor, p, fileName, language)
+ : projectLoadMonitor.ShouldMigrateProject ();
+ if (migrationType == MigrationType.Ignore) {
+ if (st.IsMigrationRequired) {
+ monitor.ReportError (string.Format ("{1} cannot open the project '{0}' unless it is migrated.", Path.GetFileName (fileName), BrandingService.ApplicationName), null);
+ throw new Exception ("The user choose not to migrate the project");
+ } else
+ return false;
+ }
+
+ var baseDir = (FilePath) Path.GetDirectoryName (fileName);
+ if (migrationType == MigrationType.BackupAndMigrate) {
+ var backupDirFirst = baseDir.Combine ("backup");
+ string backupDir = backupDirFirst;
+ int i = 0;
+ while (Directory.Exists (backupDir)) {
+ backupDir = backupDirFirst + "-" + i.ToString ();
+ if (i++ > 20) {
+ throw new Exception ("Too many backup directories");
}
}
+ Directory.CreateDirectory (backupDir);
+ foreach (var file in st.MigrationHandler.FilesToBackup (fileName))
+ File.Copy (file, Path.Combine (backupDir, Path.GetFileName (file)));
}
- else if (item is SolutionFolder) {
- MSBuildHandler h = new MSBuildHandler (FolderTypeGuid, null);
- h.Item = item;
- item.SetItemHandler (h);
+
+ var res = await st.MigrationHandler.Migrate (projectLoadMonitor, p, fileName, language);
+ if (!res)
+ throw new Exception ("Could not migrate the project");
+
+ return true;
+ }*/
+
+ internal static string GetLanguageGuid (string language)
+ {
+ foreach (var node in GetItemTypeNodes ().OfType<DotNetProjectTypeNode> ()) {
+ if (node.Language == language)
+ return node.Guid;
}
+ throw new InvalidOperationException ("Language not supported: " + language);
}
-
+
+ internal static string GetLanguageFromGuid (string guid)
+ {
+ foreach (var node in GetItemTypeNodes ().OfType<DotNetProjectTypeNode> ()) {
+ if (node.Guid.Equals (guid, StringComparison.OrdinalIgnoreCase))
+ return node.Language;
+ }
+ throw new InvalidOperationException ("Language not supported: " + guid);
+ }
+
+ internal static bool IsKnownTypeGuid (string guid)
+ {
+ foreach (var node in GetItemTypeNodes ()) {
+ if (node.Guid.Equals (guid, StringComparison.OrdinalIgnoreCase))
+ return true;
+ }
+ return false;
+ }
+
+ internal static string GetTypeGuidFromAlias (string alias)
+ {
+ foreach (var node in GetItemTypeNodes ()) {
+ if (node.Alias.Equals (alias, StringComparison.OrdinalIgnoreCase))
+ return node.Guid;
+ }
+ return null;
+ }
+
+ internal static IEnumerable<string> GetDefaultImports (string typeGuid)
+ {
+ foreach (var node in GetItemTypeNodes ()) {
+ if (node.Guid == typeGuid && !string.IsNullOrEmpty (node.Import))
+ yield return node.Import;
+ }
+ }
+
public static bool SupportsProjectType (string projectFile)
{
if (!string.IsNullOrWhiteSpace (projectFile)) {
@@ -212,9 +304,9 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return false;
}
- public static void CheckHandlerUsesMSBuildEngine (SolutionItem item, out bool useByDefault, out bool require)
+ public static void CheckHandlerUsesMSBuildEngine (SolutionFolderItem item, out bool useByDefault, out bool require)
{
- var handler = item.ItemHandler as MSBuildProjectHandler;
+ var handler = item as Project;
if (handler == null) {
useByDefault = require = false;
return;
@@ -223,88 +315,92 @@ namespace MonoDevelop.Projects.Formats.MSBuild
require = handler.RequireMSBuildEngine;
}
- internal static DotNetProjectSubtypeNode GetDotNetProjectSubtype (string typeGuids)
- {
- if (!string.IsNullOrEmpty (typeGuids))
- return GetDotNetProjectSubtype (typeGuids.Split (';').Select (t => t.Trim ()));
- else
- return null;
- }
-
- internal static DotNetProjectSubtypeNode GetDotNetProjectSubtype (IEnumerable<string> typeGuids)
- {
- Type ptype = null;
- DotNetProjectSubtypeNode foundNode = null;
- foreach (string guid in typeGuids) {
- foreach (DotNetProjectSubtypeNode st in GetItemSubtypeNodes ()) {
- if (st.SupportsType (guid)) {
- if (ptype == null || ptype.IsAssignableFrom (st.Type)) {
- ptype = st.Type;
- foundNode = st;
- }
- }
- }
- }
- return foundNode;
- }
-
- static IEnumerable<ItemTypeNode> GetItemTypeNodes ()
- {
- foreach (ExtensionNode node in AddinManager.GetExtensionNodes (ItemTypesExtensionPath)) {
- if (node is ItemTypeNode)
- yield return (ItemTypeNode) node;
- }
- yield return genericItemTypeNode;
- }
-
- internal static IEnumerable<DotNetProjectSubtypeNode> GetItemSubtypeNodes ()
+ static IEnumerable<SolutionItemTypeNode> GetItemTypeNodes ()
{
foreach (ExtensionNode node in AddinManager.GetExtensionNodes (ItemTypesExtensionPath)) {
- if (node is DotNetProjectSubtypeNode)
- yield return (DotNetProjectSubtypeNode) node;
+ if (node is SolutionItemTypeNode)
+ yield return (SolutionItemTypeNode) node;
}
}
internal static bool CanReadFile (FilePath file)
{
- foreach (ItemTypeNode node in GetItemTypeNodes ()) {
+ foreach (SolutionItemTypeNode node in GetItemTypeNodes ()) {
if (node.CanHandleFile (file, null)) {
return true;
}
}
- if (IsProjectSubtypeFile (file)) {
- string typeGuids = LoadProjectTypeGuids (file);
- foreach (ItemTypeNode node in GetItemTypeNodes ()) {
- if (node.CanHandleFile (file, typeGuids)) {
- return true;
- }
- }
- }
return GetUnknownProjectTypeInfo (new string[0], file) != null;
}
- internal static string GetExtensionForItem (SolutionEntityItem item)
+ internal static string GetExtensionForItem (SolutionItem item)
{
- foreach (DotNetProjectSubtypeNode node in GetItemSubtypeNodes ()) {
- if (!string.IsNullOrEmpty (node.Extension) && node.CanHandleItem (item))
- return node.Extension;
- }
- foreach (ItemTypeNode node in GetItemTypeNodes ()) {
- if (node.CanHandleItem (item)) {
+ foreach (SolutionItemTypeNode node in GetItemTypeNodes ()) {
+ if (node.Guid.Equals (item.TypeGuid, StringComparison.OrdinalIgnoreCase))
return node.Extension;
- }
}
// The generic handler should always be found
throw new InvalidOperationException ();
}
-
- static bool IsProjectSubtypeFile (FilePath file)
+
+ internal static string GetTypeGuidForItem (SolutionItem item)
{
- foreach (DotNetProjectSubtypeNode node in GetItemSubtypeNodes ()) {
- if (!string.IsNullOrEmpty (node.Extension) && node.CanHandleFile (file, null))
- return true;
+ var className = item.GetType ().FullName;
+ foreach (SolutionItemTypeNode node in GetItemTypeNodes ()) {
+ if (node.ItenTypeName == className)
+ return node.Guid;
+ }
+ return GenericItemGuid;
+ }
+
+ public static void RegisterGenericProjectType (string projectId, Type type)
+ {
+ lock (genericProjectTypes) {
+ if (!typeof(Project).IsAssignableFrom (type))
+ throw new ArgumentException ("Type is not a subclass of MonoDevelop.Projects.Project");
+ genericProjectTypes [projectId] = type;
+ }
+ }
+
+ internal static Task<SolutionItem> CreateGenericProject (string file)
+ {
+ return Task<SolutionItem>.Factory.StartNew (delegate {
+ var t = ReadGenericProjectType (file);
+ if (t == null)
+ throw new UserException ("Unknown project type");
+
+ Type type;
+ lock (genericProjectTypes) {
+ if (!genericProjectTypes.TryGetValue (t, out type))
+ throw new UserException ("Unknown project type: " + t);
+ }
+ return (SolutionItem)Activator.CreateInstance (type);
+ });
+ }
+
+ static string ReadGenericProjectType (string file)
+ {
+ using (XmlTextReader tr = new XmlTextReader (file)) {
+ tr.MoveToContent ();
+ if (tr.LocalName != "Project")
+ return null;
+ if (tr.IsEmptyElement)
+ return null;
+ tr.ReadStartElement ();
+ tr.MoveToContent ();
+ if (tr.LocalName != "PropertyGroup")
+ return null;
+ if (tr.IsEmptyElement)
+ return null;
+ tr.ReadStartElement ();
+ tr.MoveToContent ();
+ while (tr.NodeType != XmlNodeType.EndElement) {
+ if (tr.NodeType == XmlNodeType.Element && !tr.IsEmptyElement && tr.LocalName == "ItemType")
+ return tr.ReadElementString ();
+ tr.Skip ();
+ }
+ return null;
}
- return false;
}
static char[] specialCharacters = new char [] {'%', '$', '@', '(', ')', '\'', ';', '?' };
@@ -342,10 +438,14 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return str;
}
- public static string ToMSBuildPath (string baseDirectory, string absPath)
+ public static string ToMSBuildPath (string baseDirectory, string absPath, bool normalize = true)
{
+ if (string.IsNullOrEmpty (absPath))
+ return absPath;
if (baseDirectory != null) {
- absPath = FileService.NormalizeRelativePath (FileService.AbsoluteToRelativePath (baseDirectory, absPath));
+ absPath = FileService.AbsoluteToRelativePath (baseDirectory, absPath);
+ if (normalize)
+ absPath = FileService.NormalizeRelativePath (absPath);
}
return EscapeString (absPath).Replace ('/', '\\');
}
@@ -501,6 +601,8 @@ namespace MonoDevelop.Projects.Formats.MSBuild
extn = fname.Substring (last_dot + 1);
return true;
}
+
+ static bool runLocal = false;
internal static RemoteProjectBuilder GetProjectBuilder (TargetRuntime runtime, string minToolsVersion, string file, string solutionFile)
{
@@ -537,6 +639,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
//always start the remote process explicitly, even if it's using the current runtime and fx
//else it won't pick up the assembly redirects from the builder exe
var exe = GetExeLocation (runtime, toolsVersion);
+
MonoDevelop.Core.Execution.RemotingService.RegisterRemotingChannel ();
var pinfo = new ProcessStartInfo (exe) {
UseShellExecute = false,
@@ -547,22 +650,30 @@ namespace MonoDevelop.Projects.Formats.MSBuild
runtime.GetToolsExecutionEnvironment ().MergeTo (pinfo);
Process p = null;
+
try {
- p = runtime.ExecuteAssembly (pinfo);
- p.StandardInput.WriteLine (Process.GetCurrentProcess ().Id.ToString ());
- string responseKey = "[MonoDevelop]";
- string sref;
- while (true) {
- sref = p.StandardError.ReadLine ();
- if (sref.StartsWith (responseKey, StringComparison.Ordinal)) {
- sref = sref.Substring (responseKey.Length);
- break;
+ IBuildEngine engine;
+ if (!runLocal) {
+ p = runtime.ExecuteAssembly (pinfo);
+ p.StandardInput.WriteLine (Process.GetCurrentProcess ().Id.ToString ());
+ string responseKey = "[MonoDevelop]";
+ string sref;
+ while (true) {
+ sref = p.StandardError.ReadLine ();
+ if (sref.StartsWith (responseKey, StringComparison.Ordinal)) {
+ sref = sref.Substring (responseKey.Length);
+ break;
+ }
}
+ byte[] data = Convert.FromBase64String (sref);
+ MemoryStream ms = new MemoryStream (data);
+ BinaryFormatter bf = new BinaryFormatter ();
+ engine = (IBuildEngine)bf.Deserialize (ms);
+ } else {
+ var asm = System.Reflection.Assembly.LoadFrom (exe);
+ var t = asm.GetType ("MonoDevelop.Projects.Formats.MSBuild.BuildEngine");
+ engine = (IBuildEngine)Activator.CreateInstance (t);
}
- byte[] data = Convert.FromBase64String (sref);
- MemoryStream ms = new MemoryStream (data);
- BinaryFormatter bf = new BinaryFormatter ();
- var engine = (IBuildEngine)bf.Deserialize (ms);
engine.SetCulture (GettextCatalog.UICulture);
engine.SetGlobalProperties (GetCoreGlobalProperties (solutionFile));
foreach (var gpp in globalPropertyProviders)
@@ -572,13 +683,19 @@ namespace MonoDevelop.Projects.Formats.MSBuild
if (p != null) {
try {
p.Kill ();
- } catch { }
+ } catch {
+ }
}
throw;
}
-
+
+
builders [builderKey] = builder;
builder.ReferenceCount = 1;
+ builder.Disconnected += delegate {
+ lock (builders)
+ builders.Remove (builderKey);
+ };
return new RemoteProjectBuilder (file, builder);
}
}
@@ -623,45 +740,11 @@ namespace MonoDevelop.Projects.Formats.MSBuild
internal static void ReleaseProjectBuilder (RemoteBuildEngine engine)
{
lock (builders) {
- if (engine.ReferenceCount > 0) {
- if (--engine.ReferenceCount == 0) {
- engine.ReleaseTime = DateTime.Now.AddSeconds (3);
- ScheduleProjectBuilderCleanup (engine.ReleaseTime.AddMilliseconds (500));
- }
- }
- }
- }
-
- static DateTime nextCleanup = DateTime.MinValue;
-
- static void ScheduleProjectBuilderCleanup (DateTime cleanupTime)
- {
- lock (builders) {
- if (cleanupTime < nextCleanup)
+ if (--engine.ReferenceCount != 0)
return;
- nextCleanup = cleanupTime;
- System.Threading.ThreadPool.QueueUserWorkItem (delegate {
- DateTime tnow = DateTime.Now;
- while (tnow < nextCleanup) {
- System.Threading.Thread.Sleep ((int)(nextCleanup - tnow).TotalMilliseconds);
- CleanProjectBuilders ();
- tnow = DateTime.Now;
- }
- });
- }
- }
-
- static void CleanProjectBuilders ()
- {
- lock (builders) {
- DateTime tnow = DateTime.Now;
- foreach (var val in new Dictionary<string,RemoteBuildEngine> (builders)) {
- if (val.Value.ReferenceCount == 0 && val.Value.ReleaseTime <= tnow) {
- builders.Remove (val.Key);
- val.Value.Dispose ();
- }
- }
+ builders.Remove (builders.First (kvp => kvp.Value == engine).Key);
}
+ engine.Dispose ();
}
static Dictionary<string, string> cultureNamesTable;
@@ -682,11 +765,11 @@ namespace MonoDevelop.Projects.Formats.MSBuild
MSBuildProject project = new MSBuildProject ();
project.Load (fileName);
- MSBuildPropertySet globalGroup = project.GetGlobalPropertyGroup ();
+ IMSBuildPropertySet globalGroup = project.GetGlobalPropertyGroup ();
if (globalGroup == null)
return null;
- return globalGroup.GetPropertyValue ("ProjectTypeGuids");
+ return globalGroup.GetValue ("ProjectTypeGuids");
}
internal static UnknownProjectTypeNode GetUnknownProjectTypeInfo (string[] guids, string fileName = null)
@@ -696,11 +779,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild
.Where (p => guids.Any (p.MatchesGuid) || (ext != null && p.Extension == ext)).ToList ();
return nodes.FirstOrDefault (n => !n.IsSolvable) ?? nodes.FirstOrDefault (n => n.IsSolvable);
}
-
- public static MSBuildProjectHandler GetHandler (Project project)
- {
- return (MSBuildProjectHandler) project.GetItemHandler ();
- }
}
class MSBuildDataContext: DataContext
@@ -807,21 +885,12 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
}
- class GenericItemTypeNode: ItemTypeNode
+ [RegisterProjectType (MSBuildProjectService.GenericItemGuid, Extension="mdproj")]
+ class GenericItemFactory: SolutionItemFactory
{
- public GenericItemTypeNode (): base (MSBuildProjectService.GenericItemGuid, "mdproj", null)
- {
- }
-
- public override bool CanHandleItem (SolutionEntityItem item)
- {
- return true;
- }
-
- public override SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName, MSBuildFileFormat expectedFormat, string itemGuid)
+ public override Task<SolutionItem> CreateItem (string fileName, string typeGuid)
{
- MSBuildProjectHandler handler = new MSBuildProjectHandler (Guid, Import, itemGuid);
- return handler.Load (monitor, fileName, expectedFormat, null, null);
+ return MSBuildProjectService.CreateGenericProject (fileName);
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProperty.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProperty.cs
new file mode 100644
index 0000000000..0f5fa0422f
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProperty.cs
@@ -0,0 +1,259 @@
+//
+// MSBuildProperty.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Xml;
+using Microsoft.Build.BuildEngine;
+using System.Xml.Linq;
+using MonoDevelop.Core;
+using System.Globalization;
+
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+
+ public sealed class MSBuildProperty: MSBuildPropertyCore
+ {
+ bool preserverCase;
+ string defaultValue;
+
+ internal MSBuildProperty (MSBuildProject project, XmlElement elem): base (project, elem)
+ {
+ }
+
+ public string Name {
+ get { return Element.Name; }
+ }
+
+ public bool IsImported {
+ get;
+ set;
+ }
+
+ internal bool Overwritten { get; set; }
+
+ internal MSBuildPropertyGroup Owner { get; set; }
+
+ public bool MergeToMainGroup { get; set; }
+ internal bool HasDefaultValue { get; set; }
+
+ internal MergedProperty CreateMergedProperty ()
+ {
+ return new MergedProperty (Name, preserverCase, HasDefaultValue);
+ }
+
+ internal void SetDefaultValue (string value)
+ {
+ defaultValue = value;
+ }
+
+ public void SetValue (string value, bool preserveCase = false, bool mergeToMainGroup = false)
+ {
+ MergeToMainGroup = mergeToMainGroup;
+ this.preserverCase = preserveCase;
+
+ if (value == null)
+ value = String.Empty;
+
+ if (preserveCase) {
+ var current = GetPropertyValue ();
+ if (current != null) {
+ if (current.Equals (value, preserveCase ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture))
+ return;
+ }
+ }
+ SetPropertyValue (value);
+ }
+
+ public void SetValue (FilePath value, bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false)
+ {
+ MergeToMainGroup = mergeToMainGroup;
+ this.preserverCase = false;
+
+ string baseDir = null;
+ if (relativeToPath != null) {
+ baseDir = relativeToPath;
+ } else if (relativeToProject) {
+ baseDir = Project.BaseDirectory;
+ }
+ SetPropertyValue (MSBuildProjectService.ToMSBuildPath (baseDir, value, false));
+ }
+
+ public void SetValue (object value, bool mergeToMainGroup = false)
+ {
+ if (value is bool) {
+ if (Owner != null && Owner.UppercaseBools)
+ SetValue ((bool)value ? "True" : "False", preserveCase: true, mergeToMainGroup: mergeToMainGroup);
+ else
+ SetValue ((bool)value ? "true" : "false", preserveCase: true, mergeToMainGroup: mergeToMainGroup);
+ }
+ else
+ SetValue (Convert.ToString (value, CultureInfo.InvariantCulture), false, mergeToMainGroup);
+ }
+
+ void SetPropertyValue (string value)
+ {
+ Element.InnerText = value;
+ }
+
+ internal override string GetPropertyValue ()
+ {
+ return Element.InnerText;
+ }
+
+ public override string UnevaluatedValue {
+ get {
+ return Value;
+ }
+ }
+ }
+
+ class MSBuildPropertyEvaluated: MSBuildPropertyCore
+ {
+ string value;
+ string evaluatedValue;
+
+ internal MSBuildPropertyEvaluated (MSBuildProject project, string name, string value, string evaluatedValue): base (project, null)
+ {
+ this.evaluatedValue = evaluatedValue;
+ this.value = value;
+ Name = name;
+ }
+
+ public string Name { get; private set; }
+
+ public bool IsImported { get; set; }
+
+ public override string UnevaluatedValue {
+ get { return value; }
+ }
+
+ internal override string GetPropertyValue ()
+ {
+ return evaluatedValue;
+ }
+ }
+
+ public abstract class MSBuildPropertyCore: MSBuildObject, IMSBuildPropertyEvaluated
+ {
+ MSBuildProject project;
+
+ internal MSBuildPropertyCore (MSBuildProject project, XmlElement elem): base (elem)
+ {
+ this.project = project;
+ }
+
+ public MSBuildProject Project {
+ get { return project; }
+ }
+
+ public string Value {
+ get { return GetPropertyValue (); }
+ }
+
+ public T GetValue<T> ()
+ {
+ var val = GetPropertyValue ();
+ if (typeof(T) == typeof(bool))
+ return (T) (object) val.Equals ("true", StringComparison.InvariantCultureIgnoreCase);
+ if (typeof(T).IsEnum)
+ return (T) Enum.Parse (typeof(T), val, true);
+ return (T) Convert.ChangeType (Value, typeof(T), CultureInfo.InvariantCulture);
+ }
+
+ public object GetValue (Type t)
+ {
+ var val = GetPropertyValue ();
+ if (t == typeof(bool))
+ return (object) val.Equals ("true", StringComparison.InvariantCultureIgnoreCase);
+ return Convert.ChangeType (Value, t, CultureInfo.InvariantCulture);
+ }
+
+ public FilePath GetPathValue (bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var val = GetPropertyValue ();
+ string baseDir = null;
+
+ if (relativeToPath != null) {
+ baseDir = relativeToPath;
+ } else if (relativeToProject) {
+ baseDir = project.BaseDirectory;
+ }
+ return MSBuildProjectService.FromMSBuildPath (baseDir, val);
+ }
+
+ public bool TryGetPathValue (out FilePath value, bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var val = GetPropertyValue ();
+ string baseDir = null;
+
+ if (relativeToPath != null) {
+ baseDir = relativeToPath;
+ } else if (relativeToProject) {
+ baseDir = project.BaseDirectory;
+ }
+ string path;
+ var res = MSBuildProjectService.FromMSBuildPath (baseDir, val, out path);
+ value = path;
+ return res;
+ }
+
+ public abstract string UnevaluatedValue { get; }
+
+ internal abstract string GetPropertyValue ();
+ }
+
+ public interface IMSBuildPropertyEvaluated
+ {
+ MSBuildProject Project { get; }
+
+ string Value { get; }
+
+ string UnevaluatedValue { get; }
+
+ T GetValue<T> ();
+
+ object GetValue (Type t);
+
+ FilePath GetPathValue (bool relativeToProject = true, FilePath relativeToPath = default(FilePath));
+
+ bool TryGetPathValue (out FilePath value, bool relativeToProject = true, FilePath relativeToPath = default(FilePath));
+ }
+
+ class MergedProperty
+ {
+ public readonly string Name;
+ public readonly bool IsDefault;
+ public readonly bool PreserveExistingCase;
+
+ public MergedProperty (string name, bool preserveExistingCase, bool isDefault)
+ {
+ this.Name = name;
+ IsDefault = isDefault;
+ this.PreserveExistingCase = preserveExistingCase;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroup.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroup.cs
new file mode 100644
index 0000000000..2c7fb09bd5
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroup.cs
@@ -0,0 +1,415 @@
+//
+// MSBuildPropertyGroup.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Xml;
+
+using MonoDevelop.Core;
+using System.Xml.Linq;
+using Microsoft.Build.BuildEngine;
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+ public class MSBuildPropertyGroup: MSBuildObject, IMSBuildPropertySet, IMSBuildPropertyGroupEvaluated
+ {
+ Dictionary<string,MSBuildProperty> properties;
+ List<MSBuildProperty> propertyList = new List<MSBuildProperty> ();
+ MSBuildProject parent;
+
+ public MSBuildPropertyGroup (MSBuildProject parent, XmlElement elem): base (elem)
+ {
+ this.parent = parent;
+ }
+
+ void InitProperties ()
+ {
+ if (properties != null)
+ return;
+
+ properties = new Dictionary<string,MSBuildProperty> ();
+ propertyList = new List<MSBuildProperty> ();
+
+ foreach (var pelem in Element.ChildNodes.OfType<XmlElement> ()) {
+ MSBuildProperty prevSameName;
+ if (properties.TryGetValue (pelem.Name, out prevSameName))
+ prevSameName.Overwritten = true;
+
+ var prop = new MSBuildProperty (parent, pelem);
+ prop.Owner = this;
+ propertyList.Add (prop);
+ properties [pelem.Name] = prop; // If a property is defined more than once, we only care about the last registered value
+ }
+ }
+
+ public bool IsImported {
+ get;
+ set;
+ }
+
+ public MSBuildProject Project {
+ get {
+ return this.parent;
+ }
+ }
+
+ internal bool IgnoreDefaultValues { get; set; }
+
+ internal bool UppercaseBools { get; set; }
+
+ IMSBuildPropertyEvaluated IMSBuildPropertyGroupEvaluated.GetProperty (string name)
+ {
+ return GetProperty (name);
+ }
+
+ public MSBuildProperty GetProperty (string name)
+ {
+ return GetProperty (name, null);
+ }
+
+ public MSBuildProperty GetProperty (string name, string condition)
+ {
+ InitProperties ();
+ MSBuildProperty prop;
+ properties.TryGetValue (name, out prop);
+ return prop;
+ }
+
+ public IEnumerable<MSBuildProperty> Properties {
+ get {
+ InitProperties ();
+ return propertyList.Where (p => !p.Overwritten);
+ }
+ }
+
+ public string GetValue (string name, string defaultValue = null)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.Value;
+ else
+ return defaultValue;
+ }
+
+ public FilePath GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetPathValue (relativeToProject, relativeToPath);
+ else
+ return defaultValue;
+ }
+
+ public bool TryGetPathValue (string name, out FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.TryGetPathValue (out value, relativeToProject, relativeToPath);
+ else {
+ value = defaultValue;
+ return value != default(FilePath);
+ }
+ }
+
+ public T GetValue<T> (string name)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetValue<T> ();
+ else
+ return default(T);
+ }
+
+ public T GetValue<T> (string name, T defaultValue)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetValue<T> ();
+ else
+ return defaultValue;
+ }
+
+ public object GetValue (string name, Type type, object defaultValue)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetValue (type);
+ else
+ return defaultValue;
+ }
+
+ Dictionary<Type,object> customDataObjects = new Dictionary<Type, object> ();
+
+ public T GetObject<T> () where T:IMSBuildDataObject, new()
+ {
+ object ob;
+ if (!customDataObjects.TryGetValue (typeof(T), out ob)) {
+ customDataObjects [typeof(T)] = ob = new T ();
+ ((IMSBuildDataObject)ob).Read (this, parent.Format);
+ }
+ return (T)ob;
+ }
+
+ public void SetObject<T> (T t, bool persist = true) where T:IMSBuildDataObject
+ {
+ customDataObjects [typeof(T)] = t;
+ }
+
+ public void WriteDataObjects ()
+ {
+ foreach (IMSBuildDataObject ob in customDataObjects.Values)
+ ob.Write (this, parent.Format);
+ }
+
+ MSBuildProperty AddProperty (string name, string condition = null)
+ {
+ InitProperties ();
+ int i = propertyOrder.IndexOf (name);
+ var pelem = Element.OwnerDocument.CreateElement (null, name, MSBuildProject.Schema);
+ int insertIndex = -1;
+ if (i != -1) {
+ var foundProp = FindExistingProperty (i - 1, -1);
+ if (foundProp != null) {
+ Element.InsertAfter (pelem, foundProp.Element);
+ insertIndex = propertyList.IndexOf (foundProp) + 1;
+ } else {
+ foundProp = FindExistingProperty (i + 1, 1);
+ if (foundProp != null) {
+ Element.InsertBefore (pelem, foundProp.Element);
+ insertIndex = propertyList.IndexOf (foundProp) - 1;
+ }
+ else
+ Element.AppendChild (pelem);
+ }
+ } else
+ Element.AppendChild (pelem);
+
+ var prop = new MSBuildProperty (parent, pelem);
+ prop.Owner = this;
+ properties [name] = prop;
+
+ if (insertIndex != -1)
+ propertyList.Insert (insertIndex, prop);
+ else
+ propertyList.Add (prop);
+
+ if (condition != null)
+ prop.Condition = condition;
+ return prop;
+ }
+
+ MSBuildProperty FindExistingProperty (int index, int inc)
+ {
+ while (index >= 0 && index < propertyOrder.Count) {
+ var ep = GetProperty (propertyOrder[index]);
+ if (ep != null)
+ return ep;
+ index += inc;
+ }
+ return null;
+ }
+
+ MSBuildProperty SafeGetProperty (string name, string condition)
+ {
+ var prop = GetProperty (name, condition);
+ if (prop == null) {
+ prop = GetProperty (name);
+ if (prop != null) {
+ prop.Condition = condition;
+ return prop;
+ }
+ }
+ return AddProperty (name, condition);
+ }
+
+ public void SetValue (string name, string value, string defaultValue = null, bool preserveExistingCase = false, bool mergeToMainGroup = false, string condition = null)
+ {
+ if (value == null && defaultValue == "")
+ value = "";
+ var prop = GetProperty (name, condition);
+ var isDefault = value == defaultValue;
+ if (isDefault && !mergeToMainGroup && !IgnoreDefaultValues) {
+ // if the value is default, only remove the property if it was not already the default
+ // to avoid unnecessary project file churn
+ if (prop != null && (defaultValue == null || !string.Equals (defaultValue, prop.Value, preserveExistingCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)))
+ RemoveProperty (prop);
+ return;
+ }
+ if (prop == null)
+ prop = AddProperty (name, condition);
+ prop.SetValue (value, preserveExistingCase, mergeToMainGroup);
+ prop.HasDefaultValue = isDefault;
+ }
+
+ public void SetValue (string name, FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false, string condition = null)
+ {
+ var prop = GetProperty (name, condition);
+ var isDefault = value.CanonicalPath == defaultValue.CanonicalPath;
+ if (isDefault && !mergeToMainGroup && !IgnoreDefaultValues) {
+ // if the value is default, only remove the property if it was not already the default
+ // to avoid unnecessary project file churn
+ if (prop != null && (defaultValue == null || defaultValue != prop.GetPathValue (relativeToProject, relativeToPath)))
+ RemoveProperty (prop);
+ return;
+ }
+ if (prop == null)
+ prop = AddProperty (name, condition);
+ prop.SetValue (value, relativeToProject, relativeToPath, mergeToMainGroup);
+ prop.HasDefaultValue = isDefault;
+ }
+
+ public void SetValue (string name, object value, object defaultValue = null, bool mergeToMainGroup = false, string condition = null)
+ {
+ var prop = GetProperty (name, condition);
+ var isDefault = object.Equals (value, defaultValue);
+ if (isDefault && !mergeToMainGroup && !IgnoreDefaultValues) {
+ // if the value is default, only remove the property if it was not already the default
+ // to avoid unnecessary project file churn
+ if (prop != null && (defaultValue == null || !object.Equals (defaultValue, prop.GetValue (defaultValue.GetType ()))))
+ RemoveProperty (prop);
+ return;
+ }
+ if (prop == null)
+ prop = AddProperty (name, condition);
+ prop.SetValue (value, mergeToMainGroup);
+ prop.HasDefaultValue = isDefault;
+ }
+
+ public bool RemoveProperty (string name)
+ {
+ MSBuildProperty prop = GetProperty (name);
+ if (prop != null) {
+ RemoveProperty (prop);
+ return true;
+ }
+ return false;
+ }
+
+ public void RemoveProperty (MSBuildProperty prop)
+ {
+ InitProperties ();
+ properties.Remove (prop.Name);
+ propertyList.Remove (prop);
+ Element.RemoveChild (prop.Element);
+ }
+
+ public void RemoveAllProperties ()
+ {
+ InitProperties ();
+ List<XmlNode> toDelete = new List<XmlNode> ();
+ foreach (XmlNode node in Element.ChildNodes) {
+ if (node is XmlElement)
+ toDelete.Add (node);
+ }
+ foreach (XmlNode node in toDelete)
+ Element.RemoveChild (node);
+ properties.Clear ();
+ propertyList.Clear ();
+ }
+
+ public void UnMerge (IMSBuildPropertySet baseGrp, ISet<string> propsToExclude)
+ {
+ HashSet<string> baseProps = new HashSet<string> ();
+ foreach (MSBuildProperty prop in baseGrp.Properties) {
+ if (propsToExclude != null && propsToExclude.Contains (prop.Name))
+ continue;
+ baseProps.Add (prop.Name);
+ MSBuildProperty thisProp = GetProperty (prop.Name);
+ if (thisProp != null && prop.Value.Equals (thisProp.Value, StringComparison.OrdinalIgnoreCase))
+ RemoveProperty (prop.Name);
+ }
+
+ // Remove properties which have the default value and which are not defined in the main group
+ foreach (var p in Properties.ToArray ()) {
+ if (baseProps.Contains (p.Name))
+ continue;
+ if (p.HasDefaultValue)
+ RemoveProperty (p);
+ }
+ }
+
+ public override string ToString()
+ {
+ string s = "[MSBuildPropertyGroup:";
+ foreach (MSBuildProperty prop in Properties)
+ s += " " + prop.Name + "=" + prop.Value;
+ return s + "]";
+ }
+
+ public void SetObject<T> (T t) where T : IMSBuildDataObject
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool HasProperty (string name)
+ {
+ InitProperties ();
+ return properties.ContainsKey (name);
+ }
+
+ List<string> propertyOrder = new List<string> ();
+
+ public void SetPropertyOrder (params string[] propertyNames)
+ {
+ int i = 0;
+ foreach (var name in propertyNames) {
+ if (i < propertyOrder.Count) {
+ var pos = propertyOrder.IndexOf (name, i);
+ if (pos != -1) {
+ i = pos + 1;
+ continue;
+ } else {
+ propertyOrder.Insert (i, name);
+ i++;
+ continue;
+ }
+ }
+ propertyOrder.Add (name);
+ i++;
+ }
+ }
+ }
+
+ public interface IMSBuildPropertyGroupEvaluated
+ {
+ bool HasProperty (string name);
+
+ IMSBuildPropertyEvaluated GetProperty (string name);
+
+ string GetValue (string name, string defaultValue = null);
+
+ FilePath GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath));
+
+ bool TryGetPathValue (string name, out FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath));
+
+ T GetValue<T> (string name);
+
+ T GetValue<T> (string name, T defaultValue);
+
+ object GetValue (string name, Type type, object defaultValue);
+ }
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroupEvaluated.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroupEvaluated.cs
new file mode 100644
index 0000000000..2ffc9d9d1b
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroupEvaluated.cs
@@ -0,0 +1,155 @@
+//
+// MSBuildPropertyGroupEvaluated.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using System.Xml.Linq;
+using MonoDevelop.Core;
+using Microsoft.Build.BuildEngine;
+using MSProject = Microsoft.Build.BuildEngine.Project;
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+ class MSBuildPropertyGroupEvaluated: IMSBuildPropertyGroupEvaluated
+ {
+ internal Dictionary<string,MSBuildPropertyEvaluated> properties = new Dictionary<string, MSBuildPropertyEvaluated> ();
+ internal MSBuildProject parent;
+ BuildItem sourceItem;
+
+ internal MSBuildPropertyGroupEvaluated (MSBuildProject parent)
+ {
+ this.parent = parent;
+ }
+
+ internal void Sync (BuildItem item)
+ {
+ properties.Clear ();
+ sourceItem = item;
+ }
+
+ public bool HasProperty (string name)
+ {
+ if (!properties.ContainsKey (name)) {
+ if (sourceItem != null)
+ return sourceItem.HasMetadata (name);
+ }
+ return false;
+ }
+
+ public IMSBuildPropertyEvaluated GetProperty (string name)
+ {
+ MSBuildPropertyEvaluated prop;
+ if (!properties.TryGetValue (name, out prop)) {
+ if (sourceItem != null) {
+ if (sourceItem.HasMetadata (name)) {
+ prop = new MSBuildPropertyEvaluated (parent, name, sourceItem.GetMetadata (name), sourceItem.GetEvaluatedMetadata (name));
+ properties [name] = prop;
+ }
+ }
+ }
+ return prop;
+ }
+
+ public string GetValue (string name, string defaultValue = null)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.Value;
+ else
+ return defaultValue;
+ }
+
+ public FilePath GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetPathValue (relativeToProject, relativeToPath);
+ else
+ return defaultValue;
+ }
+
+ public bool TryGetPathValue (string name, out FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.TryGetPathValue (out value, relativeToProject, relativeToPath);
+ else {
+ value = defaultValue;
+ return value != default(FilePath);
+ }
+ }
+
+ public T GetValue<T> (string name)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetValue<T> ();
+ else
+ return default(T);
+ }
+
+ public T GetValue<T> (string name, T defaultValue)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetValue<T> ();
+ else
+ return defaultValue;
+ }
+
+ public object GetValue (string name, Type type, object defaultValue)
+ {
+ var prop = GetProperty (name);
+ if (prop != null)
+ return prop.GetValue (type);
+ else
+ return defaultValue;
+ }
+ }
+
+ class MSBuildEvaluatedPropertyCollection: MSBuildPropertyGroupEvaluated, IMSBuildEvaluatedPropertyCollection
+ {
+ public MSBuildEvaluatedPropertyCollection (MSBuildProject parent): base (parent)
+ {
+ }
+
+ internal void Sync (BuildPropertyGroup msgroup)
+ {
+ properties.Clear ();
+ foreach (BuildProperty p in msgroup)
+ properties [p.Name] = new MSBuildPropertyEvaluated (parent, p.Name, p.Value, p.FinalValue);
+ }
+
+ public IEnumerable<IMSBuildPropertyEvaluated> Properties {
+ get { return properties.Values; }
+ }
+ }
+
+ public interface IMSBuildEvaluatedPropertyCollection: IMSBuildPropertyGroupEvaluated
+ {
+ IEnumerable<IMSBuildPropertyEvaluated> Properties { get; }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroupMerged.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroupMerged.cs
new file mode 100644
index 0000000000..11117a97e6
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildPropertyGroupMerged.cs
@@ -0,0 +1,234 @@
+//
+// MSBuildPropertyGroupMerged.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Xml;
+
+using MonoDevelop.Core;
+using System.Xml.Linq;
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+
+ class MSBuildPropertyGroupMerged: IMSBuildPropertySet
+ {
+ List<IMSBuildPropertySet> groups = new List<IMSBuildPropertySet> ();
+ MSBuildFileFormat format;
+
+ public MSBuildPropertyGroupMerged (MSBuildProject project, MSBuildFileFormat format)
+ {
+ this.format = format;
+ Project = project;
+ }
+
+ public MSBuildProject Project { get; private set; }
+
+ public string Label { get; set; }
+
+ public void Add (IMSBuildPropertySet g)
+ {
+ groups.Add (g);
+ }
+
+ public int GroupCount {
+ get { return groups.Count; }
+ }
+
+ public MSBuildProperty GetProperty (string name)
+ {
+ // Find property in reverse order, since the last set
+ // value is the good one
+ for (int n=groups.Count - 1; n >= 0; n--) {
+ var g = groups [n];
+ MSBuildProperty p = g.GetProperty (name);
+ if (p != null)
+ return p;
+ }
+ return null;
+ }
+
+ public IMSBuildPropertySet GetGroupForProperty (string name)
+ {
+ // Find property in reverse order, since the last set
+ // value is the good one
+ for (int n=groups.Count - 1; n >= 1; n--) {
+ var g = groups [n];
+ MSBuildProperty p = g.GetProperty (name);
+ if (p != null)
+ return g;
+ }
+ return groups[0];
+ }
+
+ Dictionary<Type,object> customDataObjects = new Dictionary<Type, object> ();
+
+ public T GetObject<T> () where T:IMSBuildDataObject, new()
+ {
+ object ob;
+ if (!customDataObjects.TryGetValue (typeof(T), out ob)) {
+ customDataObjects [typeof(T)] = ob = new T ();
+ ((IMSBuildDataObject)ob).Read (this, format);
+ }
+ return (T)ob;
+ }
+
+ public void SetObject<T> (T t, bool persist = true) where T:IMSBuildDataObject
+ {
+ customDataObjects [typeof(T)] = t;
+ }
+
+ public void WriteDataObjects ()
+ {
+ foreach (IMSBuildDataObject ob in customDataObjects.Values)
+ ob.Write (this, format);
+ }
+
+ public void SetPropertyValue (string name, string value, bool preserveExistingCase)
+ {
+ MSBuildProperty p = GetProperty (name);
+ if (p != null) {
+ if (!preserveExistingCase || !string.Equals (value, p.Value, StringComparison.OrdinalIgnoreCase)) {
+ p.SetValue (value);
+ }
+ return;
+ }
+ groups [0].SetValue (name, value, preserveExistingCase:preserveExistingCase);
+ }
+
+ public void SetValue (string name, string value, string defaultValue = null, bool preserveExistingCase = false, bool mergeToMainGroup = false, string condition = null)
+ {
+ GetGroupForProperty (name).SetValue (name, value, defaultValue, preserveExistingCase, mergeToMainGroup, condition);
+ }
+
+ public void SetValue (string name, FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath), bool mergeToMainGroup = false, string condition = null)
+ {
+ GetGroupForProperty (name).SetValue (name, value, defaultValue, relativeToProject, relativeToPath, mergeToMainGroup, condition);
+ }
+
+ public void SetValue (string name, object value, object defaultValue = null, bool mergeToMainGroup = false, string condition = null)
+ {
+ GetGroupForProperty (name).SetValue (name, value, defaultValue, mergeToMainGroup, condition);
+ }
+
+ public string GetValue (string name, string defaultValue = null)
+ {
+ return GetGroupForProperty (name).GetValue (name, defaultValue);
+ }
+
+ public string GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToFile = true)
+ {
+ return GetGroupForProperty (name).GetPathValue (name, defaultValue, relativeToFile);
+ }
+
+ public T GetValue<T> (string name)
+ {
+ return GetGroupForProperty (name).GetValue<T> (name);
+ }
+
+ public T GetValue<T> (string name, T defaultValue)
+ {
+ return GetGroupForProperty (name).GetValue<T> (name, defaultValue);
+ }
+
+ public object GetValue (string name, Type type, object defaultValue)
+ {
+ return GetGroupForProperty (name).GetValue (name, type, defaultValue);
+ }
+
+ public bool RemoveProperty (string name)
+ {
+ bool found = false;
+ foreach (var g in groups) {
+ if (g.RemoveProperty (name)) {
+ Prune ((MSBuildPropertyGroup)g);
+ found = true;
+ }
+ }
+ return found;
+ }
+
+ public void RemoveAllProperties ()
+ {
+ foreach (var g in groups) {
+ g.RemoveAllProperties ();
+ Prune ((MSBuildPropertyGroup)g);
+ }
+ }
+
+ public void UnMerge (IMSBuildPropertySet baseGrp, ISet<string> propertiesToExclude)
+ {
+ foreach (var g in groups) {
+ ((MSBuildPropertyGroup)g).UnMerge (baseGrp, propertiesToExclude);
+ }
+ }
+
+ public IEnumerable<MSBuildProperty> Properties {
+ get {
+ foreach (var g in groups) {
+ foreach (var p in g.Properties)
+ yield return p;
+ }
+ }
+ }
+
+ void Prune (MSBuildPropertyGroup g)
+ {
+ if (g != groups [0] && !g.Properties.Any()) {
+ // Remove this group since it's now empty
+ g.Project.RemoveGroup (g);
+ }
+ }
+
+ public void SetObject<T> (T t) where T : IMSBuildDataObject
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool HasProperty (string name)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public FilePath GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ return GetGroupForProperty (name).GetPathValue (name, defaultValue, relativeToProject, relativeToPath);
+ }
+
+ public bool TryGetPathValue (string name, out FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, FilePath relativeToPath = default(FilePath))
+ {
+ return GetGroupForProperty (name).TryGetPathValue (name, out value, defaultValue, relativeToProject, relativeToPath);
+ }
+
+ public void SetPropertyOrder (params string[] propertyNames)
+ {
+ foreach (var g in groups)
+ g.SetPropertyOrder (propertyNames);
+ }
+ }
+
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/RemoteProjectBuilder.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/RemoteProjectBuilder.cs
index e5d99fb724..d2cefb444b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/RemoteProjectBuilder.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/RemoteProjectBuilder.cs
@@ -30,6 +30,9 @@ using System.Globalization;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using MonoDevelop.Core;
+using System.IO;
+using System.Linq;
namespace MonoDevelop.Projects.Formats.MSBuild
{
@@ -37,6 +40,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
{
IBuildEngine engine;
Process proc;
+ bool alive = true;
public int ReferenceCount { get; set; }
public DateTime ReleaseTime { get; set; }
@@ -47,36 +51,92 @@ namespace MonoDevelop.Projects.Formats.MSBuild
this.engine = engine;
}
+ public event EventHandler Disconnected;
+
public IProjectBuilder LoadProject (string projectFile)
{
- return engine.LoadProject (projectFile);
+ try {
+ return engine.LoadProject (projectFile);
+ } catch {
+ CheckDisconnected ();
+ throw;
+ }
}
public void UnloadProject (IProjectBuilder pb)
{
- engine.UnloadProject (pb);
+ try {
+ engine.UnloadProject (pb);
+ } catch (Exception ex) {
+ LoggingService.LogError ("Project unloading failed", ex);
+ if (!CheckDisconnected ())
+ throw;
+ }
}
public void SetCulture (CultureInfo uiCulture)
{
- engine.SetCulture (uiCulture);
+ try {
+ engine.SetCulture (uiCulture);
+ } catch {
+ CheckDisconnected ();
+ throw;
+ }
}
public void SetGlobalProperties (IDictionary<string, string> properties)
{
- engine.SetGlobalProperties (properties);
+ try {
+ engine.SetGlobalProperties (properties);
+ } catch {
+ CheckDisconnected ();
+ throw;
+ }
+ }
+
+ void IBuildEngine.Ping ()
+ {
+ engine.Ping ();
}
-
+
+ bool CheckAlive ()
+ {
+ if (!alive)
+ return false;
+ try {
+ engine.Ping ();
+ return true;
+ } catch {
+ alive = false;
+ return false;
+ }
+ }
+
+ internal bool CheckDisconnected ()
+ {
+ if (!CheckAlive ()) {
+ if (Disconnected != null)
+ Disconnected (this, EventArgs.Empty);
+ return true;
+ }
+ return false;
+ }
+
public void Dispose ()
{
- if (proc != null) {
- try {
- proc.Kill ();
- } catch {
+ try {
+ alive = false;
+ if (proc != null) {
+ try {
+ proc.Kill ();
+ } catch {
+ }
}
+ else
+ engine.Dispose ();
+ } catch {
+ // Ignore
}
- else
- engine.Dispose ();
}
}
@@ -84,11 +144,25 @@ namespace MonoDevelop.Projects.Formats.MSBuild
{
RemoteBuildEngine engine;
IProjectBuilder builder;
-
+ Dictionary<string,string[]> referenceCache;
+ string file;
+
internal RemoteProjectBuilder (string file, RemoteBuildEngine engine)
{
+ this.file = file;
this.engine = engine;
builder = engine.LoadProject (file);
+ referenceCache = new Dictionary<string, string[]> ();
+ }
+
+ public event EventHandler Disconnected;
+
+ void CheckDisconnected ()
+ {
+ if (engine.CheckDisconnected ()) {
+ if (Disconnected != null)
+ Disconnected (this, EventArgs.Empty);
+ }
}
public MSBuildResult Run (
@@ -99,17 +173,70 @@ namespace MonoDevelop.Projects.Formats.MSBuild
string[] evaluateItems,
string[] evaluateProperties)
{
- return builder.Run (configurations, logWriter, verbosity, runTargets, evaluateItems, evaluateProperties);
+ try {
+ return builder.Run (configurations, logWriter, verbosity, runTargets, evaluateItems, evaluateProperties);
+ } catch (Exception ex) {
+ CheckDisconnected ();
+ LoggingService.LogError ("RunTarget failed", ex);
+ MSBuildTargetResult err = new MSBuildTargetResult (file, false, "", "", file, 1, 1, 1, 1, "Unknown MSBuild failure. Please try building the project again", "");
+ MSBuildResult res = new MSBuildResult (new [] { err });
+ return res;
+ }
}
-
+
+ public string[] ResolveAssemblyReferences (ProjectConfigurationInfo[] configurations)
+ {
+ string[] refs = null;
+ var id = configurations [0].Configuration + "|" + configurations [0].Platform;
+
+ lock (referenceCache) {
+ if (!referenceCache.TryGetValue (id, out refs)) {
+ MSBuildResult result;
+ try {
+ result = builder.Run (
+ configurations, null, MSBuildVerbosity.Normal,
+ new[] { "ResolveAssemblyReferences" }, new [] { "ReferencePath" }, null
+ );
+ } catch (Exception ex) {
+ CheckDisconnected ();
+ LoggingService.LogError ("ResolveAssemblyReferences failed", ex);
+ return new string[0];
+ }
+
+ List<MSBuildEvaluatedItem> items;
+ if (result.Items.TryGetValue ("ReferencePath", out items) && items != null) {
+ refs = items.Select (i => i.ItemSpec).ToArray ();
+ } else
+ refs = new string[0];
+
+ referenceCache [id] = refs;
+ }
+ }
+ return refs;
+ }
+
public void Refresh ()
{
- builder.Refresh ();
+ lock (referenceCache)
+ referenceCache.Clear ();
+ try {
+ builder.Refresh ();
+ } catch (Exception ex) {
+ LoggingService.LogError ("MSBuild refresh failed", ex);
+ CheckDisconnected ();
+ }
}
public void RefreshWithContent (string projectContent)
{
- builder.RefreshWithContent (projectContent);
+ lock (referenceCache)
+ referenceCache.Clear ();
+ try {
+ builder.RefreshWithContent (projectContent);
+ } catch (Exception ex) {
+ LoggingService.LogError ("MSBuild refresh failed", ex);
+ CheckDisconnected ();
+ }
}
public void Dispose ()
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnData.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnData.cs
deleted file mode 100644
index 9f602a5dff..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnData.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-//
-// SlnData.cs
-//
-// Author:
-// Ankit Jain <jankit@novell.com>
-//
-// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using MonoDevelop.Projects;
-
-using System;
-using System.Collections.Generic;
-
-namespace MonoDevelop.Projects.Formats.MSBuild
-{
- class SlnData
- {
- string headerComment = "# MonoDevelop";
- Dictionary<SolutionConfiguration, string> configStrings;
- List<string> globalExtra; // unused GlobalSections
- Dictionary<string, List<string>> sectionExtras;
- string[] extra; //used by solution folders..
- List<string> unknownProjects;
- Dictionary<string, SolutionEntityItem> projectsByGuidTable;
-
- public void UpdateVersion (MSBuildFileFormat format)
- {
- VersionString = format.SlnVersion;
- headerComment = "# " + format.ProductDescription;
- }
-
- // Eg. "# Visual C# Express 2008"
- public string HeaderComment {
- get { return headerComment; }
- set { headerComment = value; }
- }
-
- // Eg. 9.00 or 10.00
- public string VersionString { get; set; }
-
- public Version VisualStudioVersion { get; set; }
-
- public Version MinimumVisualStudioVersion { get; set; }
-
- public Dictionary<SolutionConfiguration, string> ConfigStrings {
- get {
- if (configStrings == null)
- configStrings = new Dictionary<SolutionConfiguration, string> ();
- return configStrings;
- }
- }
-
- public List<string> GlobalExtra {
- get { return globalExtra; }
- set { globalExtra = value; }
- }
-
- public string[] Extra {
- get { return extra; }
- set { extra = value; }
- }
-
- public List<string> UnknownProjects {
- get {
- if (unknownProjects == null)
- unknownProjects = new List<string> ();
- return unknownProjects;
- }
- }
-
- //Extra lines per section which need to be preserved
- //eg. lines in ProjectConfigurationPlatforms for projects
- //that we couldn't load
- public Dictionary<string, List<string>> SectionExtras {
- get {
- if (sectionExtras == null)
- sectionExtras = new Dictionary<string, List<string>> ();
- return sectionExtras;
- }
- }
-
- public Dictionary<string, SolutionEntityItem> ItemsByGuid {
- get {
- if (projectsByGuidTable == null)
- projectsByGuidTable = new Dictionary<string, SolutionEntityItem> ();
- return projectsByGuidTable;
- }
- }
-
- }
-
- class ItemSlnData
- {
- List<string> configLines;
-
- public List<string> ConfigLines {
- get {
- if (configLines == null)
- configLines = new List<string> ();
- return configLines;
- }
- }
-
- public static ItemSlnData ForItem (SolutionItem item)
- {
- ItemSlnData data = (ItemSlnData) item.ExtendedProperties [typeof(ItemSlnData)];
- if (data == null) {
- data = new ItemSlnData ();
- item.ExtendedProperties [typeof(ItemSlnData)] = data;
- }
- return data;
- }
-
- public static void TransferData (SolutionItem source, SolutionItem target)
- {
- ItemSlnData data = (ItemSlnData) source.ExtendedProperties [typeof(ItemSlnData)];
- if (data != null)
- target.ExtendedProperties [typeof(ItemSlnData)] = data;
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFile.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFile.cs
new file mode 100644
index 0000000000..ba9c875b75
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFile.cs
@@ -0,0 +1,581 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.IO;
+using System.Collections;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+ public class SlnFile
+ {
+ SlnProjectCollection projects = new SlnProjectCollection ();
+ SlnSectionCollection sections = new SlnSectionCollection ();
+ SlnPropertySet metadata = new SlnPropertySet (true);
+
+ public string FormatVersion { get; set; }
+ public string ProductDescription { get; set; }
+
+ public string VisualStudioVersion {
+ get { return metadata.GetValue ("VisualStudioVersion"); }
+ set { metadata.SetValue ("VisualStudioVersion", value); }
+ }
+
+ public string MinimumVisualStudioVersion {
+ get { return metadata.GetValue ("MinimumVisualStudioVersion"); }
+ set { metadata.SetValue ("MinimumVisualStudioVersion", value); }
+ }
+
+ public SlnFile ()
+ {
+ }
+
+ /// <summary>
+ /// The directory to be used as base for converting absolute paths to relative
+ /// </summary>
+ public FilePath BaseDirectory {
+ get;
+ set;
+ }
+
+ public SlnPropertySet SolutionConfigurationsSection {
+ get { return sections.GetOrCreateSection ("SolutionConfigurationPlatforms", "preSolution").Properties; }
+ }
+
+ public SlnPropertySetCollection ProjectConfigurationsSection {
+ get { return sections.GetOrCreateSection ("ProjectConfigurationPlatforms", "postSolution").NestedPropertySets; }
+ }
+
+ public SlnSectionCollection Sections {
+ get { return sections; }
+ }
+
+ public SlnProjectCollection Projects {
+ get { return projects; }
+ }
+
+ public void Read (string file)
+ {
+ using (var sr = new StreamReader (file))
+ Read (sr);
+ }
+
+ public void Read (TextReader reader)
+ {
+ string line;
+ int curLineNum = 0;
+ bool globalFound = false;
+ bool productRead = false;
+
+ while ((line = reader.ReadLine ()) != null) {
+ curLineNum++;
+ line = line.Trim ();
+ if (line.StartsWith ("Microsoft Visual Studio Solution File")) {
+ int i = line.LastIndexOf (' ');
+ if (i == -1)
+ throw new InvalidSolutionFormatException (curLineNum);
+ FormatVersion = line.Substring (i + 1);
+ }
+ if (line.StartsWith ("# ")) {
+ if (!productRead) {
+ productRead = true;
+ ProductDescription = line.Substring (2);
+ }
+ } else if (line.StartsWith ("Project")) {
+ SlnProject p = new SlnProject ();
+ p.Read (reader, line, ref curLineNum);
+ projects.Add (p);
+ } else if (line == "Global") {
+ if (globalFound)
+ throw new InvalidSolutionFormatException (curLineNum, "Global section specified more than once");
+ globalFound = true;
+ while ((line = reader.ReadLine ()) != null) {
+ curLineNum++;
+ line = line.Trim ();
+ if (line == "EndGlobal") {
+ break;
+ } else if (line.StartsWith ("GlobalSection")) {
+ var sec = new SlnSection ();
+ sec.Read (reader, line, ref curLineNum);
+ sections.Add (sec);
+ } else
+ throw new InvalidSolutionFormatException (curLineNum);
+ }
+ if (line == null)
+ throw new InvalidSolutionFormatException (curLineNum, "Global section not closed");
+ } else if (line.IndexOf ('=') != -1) {
+ metadata.ReadLine (line, curLineNum);
+ }
+ }
+ if (FormatVersion == null)
+ throw new InvalidSolutionFormatException (curLineNum, "File header is missing");
+ }
+
+ public void Write (string file)
+ {
+ using (var sw = new StreamWriter (file))
+ Write (sw);
+ }
+
+ public void Write (TextWriter writer)
+ {
+ writer.NewLine = "\r\n";
+ writer.WriteLine ("\r\nMicrosoft Visual Studio Solution File, Format Version " + FormatVersion);
+ writer.WriteLine ("# " + ProductDescription);
+
+ metadata.Write (writer);
+
+ foreach (var p in projects)
+ p.Write (writer);
+
+ writer.WriteLine ("Global");
+ foreach (SlnSection s in sections)
+ s.Write (writer, "GlobalSection");
+ writer.WriteLine ("EndGlobal");
+ }
+ }
+
+ public class SlnProject
+ {
+ SlnSectionCollection sections = new SlnSectionCollection ();
+
+ public string Id { get; set; }
+ public string TypeGuid { get; set; }
+ public string Name { get; set; }
+ public string FilePath { get; set; }
+ public int Line { get; private set; }
+ internal bool Processed { get; set; }
+
+ public SlnSectionCollection Sections {
+ get { return sections; }
+ }
+
+ internal void Read (TextReader reader, string line, ref int curLineNum)
+ {
+ Line = curLineNum;
+
+ int n = 0;
+ FindNext (curLineNum, line, ref n, '(');
+ n++;
+ FindNext (curLineNum, line, ref n, '"');
+ int n2 = n + 1;
+ FindNext (curLineNum, line, ref n2, '"');
+ TypeGuid = line.Substring (n + 1, n2 - n - 1);
+
+ n = n2 + 1;
+ FindNext (curLineNum, line, ref n, ')');
+ FindNext (curLineNum, line, ref n, '=');
+
+ FindNext (curLineNum, line, ref n, '"');
+ n2 = n + 1;
+ FindNext (curLineNum, line, ref n2, '"');
+ Name = line.Substring (n + 1, n2 - n - 1);
+
+ n = n2 + 1;
+ FindNext (curLineNum, line, ref n, ',');
+ FindNext (curLineNum, line, ref n, '"');
+ n2 = n + 1;
+ FindNext (curLineNum, line, ref n2, '"');
+ FilePath = line.Substring (n + 1, n2 - n - 1);
+
+ n = n2 + 1;
+ FindNext (curLineNum, line, ref n, ',');
+ FindNext (curLineNum, line, ref n, '"');
+ n2 = n + 1;
+ FindNext (curLineNum, line, ref n2, '"');
+ Id = line.Substring (n + 1, n2 - n - 1);
+
+ while ((line = reader.ReadLine ()) != null) {
+ curLineNum++;
+ line = line.Trim ();
+ if (line == "EndProject") {
+ return;
+ }
+ if (line.StartsWith ("ProjectSection")) {
+ if (sections == null)
+ sections = new SlnSectionCollection ();
+ var sec = new SlnSection ();
+ sections.Add (sec);
+ sec.Read (reader, line, ref curLineNum);
+ }
+ }
+
+ throw new InvalidSolutionFormatException (curLineNum, "Project section not closed");
+ }
+
+ void FindNext (int ln, string line, ref int i, char c)
+ {
+ i = line.IndexOf (c, i);
+ if (i == -1)
+ throw new InvalidSolutionFormatException (ln);
+ }
+
+ public void Write (TextWriter writer)
+ {
+ writer.Write ("Project(\"");
+ writer.Write (TypeGuid);
+ writer.Write ("\") = \"");
+ writer.Write (Name);
+ writer.Write ("\", \"");
+ writer.Write (FilePath);
+ writer.Write ("\", \"");
+ writer.Write (Id);
+ writer.WriteLine ("\"");
+ if (sections != null) {
+ foreach (SlnSection s in sections)
+ s.Write (writer, "ProjectSection");
+ }
+ writer.WriteLine ("EndProject");
+ }
+ }
+
+ public class SlnSection
+ {
+ SlnPropertySetCollection nestedPropertySets;
+ SlnPropertySet properties;
+ List<string> sectionLines;
+ int baseIndex;
+
+ public string Id { get; set; }
+ public int Line { get; private set; }
+ internal bool Processed { get; set; }
+
+ public SlnPropertySet Properties {
+ get {
+ if (properties == null) {
+ properties = new SlnPropertySet ();
+ if (sectionLines != null) {
+ foreach (var line in sectionLines)
+ properties.ReadLine (line, Line);
+ sectionLines = null;
+ }
+ }
+ return properties;
+ }
+ }
+
+ public SlnPropertySetCollection NestedPropertySets {
+ get {
+ if (nestedPropertySets == null) {
+ nestedPropertySets = new SlnPropertySetCollection ();
+ if (sectionLines != null)
+ LoadPropertySets ();
+ }
+ return nestedPropertySets;
+ }
+ }
+
+ public string SectionType { get; set; }
+
+ internal void Read (TextReader reader, string line, ref int curLineNum)
+ {
+ Line = curLineNum;
+ int k = line.IndexOf ('(');
+ if (k == -1)
+ throw new InvalidSolutionFormatException (curLineNum, "Section id missing");
+ var tag = line.Substring (0, k).Trim ();
+ var k2 = line.IndexOf (')', k);
+ if (k2 == -1)
+ throw new InvalidSolutionFormatException (curLineNum);
+ Id = line.Substring (k + 1, k2 - k - 1);
+
+ k = line.IndexOf ('=', k2);
+ SectionType = line.Substring (k + 1).Trim ();
+
+ var endTag = "End" + tag;
+
+ sectionLines = new List<string> ();
+ baseIndex = ++curLineNum;
+ while ((line = reader.ReadLine()) != null) {
+ curLineNum++;
+ line = line.Trim ();
+ if (line == endTag)
+ break;
+ sectionLines.Add (line);
+ }
+ if (line == null)
+ throw new InvalidSolutionFormatException (curLineNum, "Closing section tag not found");
+ }
+
+ void LoadPropertySets ()
+ {
+ if (sectionLines != null) {
+ SlnPropertySet curSet = null;
+ for (int n = 0; n < sectionLines.Count; n++) {
+ var line = sectionLines [n];
+ var i = line.IndexOf ('.');
+ if (i == -1)
+ throw new InvalidSolutionFormatException (baseIndex + i);
+ var id = line.Substring (0, i);
+ if (curSet == null || id != curSet.Id) {
+ curSet = new SlnPropertySet (id);
+ nestedPropertySets.Add (curSet);
+ }
+ curSet.ReadLine (line.Substring (i + 1), baseIndex + i);
+ }
+ sectionLines = null;
+ }
+ }
+
+ internal void Write (TextWriter writer, string sectionTag)
+ {
+ writer.Write ("\t");
+ writer.Write (sectionTag);
+ writer.Write ('(');
+ writer.Write (Id);
+ writer.Write (") = ");
+ writer.WriteLine (SectionType);
+ if (sectionLines != null) {
+ foreach (var l in sectionLines)
+ writer.WriteLine ("\t\t" + l);
+ } else if (properties != null)
+ properties.Write (writer);
+ else if (nestedPropertySets != null) {
+ foreach (var ps in nestedPropertySets)
+ ps.Write (writer);
+ }
+ writer.WriteLine ("\tEnd" + sectionTag);
+ }
+ }
+
+ public class SlnPropertySet: IDictionary<string,string>
+ {
+ OrderedDictionary values = new OrderedDictionary ();
+ bool isMetadata;
+
+ internal bool Processed { get; set; }
+ public int Line { get; private set; }
+
+ public SlnPropertySet ()
+ {
+ }
+
+ public SlnPropertySet (string id)
+ {
+ Id = id;
+ }
+
+ internal SlnPropertySet (bool isMetadata)
+ {
+ this.isMetadata = isMetadata;
+ }
+
+ internal void ReadLine (string line, int currentLine)
+ {
+ if (Line == 0)
+ Line = currentLine;
+ line = line.Trim ();
+ int k = line.IndexOf ('=');
+ if (k != -1) {
+ var name = line.Substring (0, k).Trim ();
+ var val = line.Substring (k + 1).Trim ();
+ values.Add (name, val);
+ } else {
+ values.Add (line, null);
+ }
+ }
+
+ internal void Write (TextWriter writer)
+ {
+ foreach (DictionaryEntry e in values) {
+ if (!isMetadata)
+ writer.Write ("\t\t");
+ if (Id != null)
+ writer.Write (Id + ".");
+ writer.WriteLine (e.Key + " = " + e.Value);
+ }
+ }
+
+ public string Id { get; private set; }
+
+ public string GetValue (string key)
+ {
+ return (string) values [key];
+ }
+
+ public void SetValue (string key, string value)
+ {
+ values [key] = value;
+ }
+
+ public void Add (string key, string value)
+ {
+ SetValue (key, value);
+ }
+
+ public bool ContainsKey (string key)
+ {
+ return values.Contains (key);
+ }
+
+ public bool Remove (string key)
+ {
+ var wasThere = values.Contains (key);
+ values.Remove (key);
+ return wasThere;
+ }
+
+ public bool TryGetValue (string key, out string value)
+ {
+ value = (string) values [key];
+ return value != null;
+ }
+
+ public string this [string index] {
+ get {
+ return (string) values [index];
+ }
+ set {
+ values [index] = value;
+ }
+ }
+
+ public ICollection<string> Values {
+ get {
+ return values.Values.Cast<string>().ToList ();
+ }
+ }
+
+ public ICollection<string> Keys {
+ get { return values.Keys.Cast<string> ().ToList (); }
+ }
+
+ public void Add (KeyValuePair<string, string> item)
+ {
+ SetValue (item.Key, item.Value);
+ }
+
+ public void Clear ()
+ {
+ values.Clear ();
+ }
+
+ internal void ClearExcept (HashSet<string> keys)
+ {
+ foreach (var k in values.Keys.Cast<string>().Except (keys).ToArray ())
+ values.Remove (k);
+ }
+
+ public bool Contains (KeyValuePair<string, string> item)
+ {
+ var val = GetValue (item.Key);
+ return val == item.Value;
+ }
+
+ public void CopyTo (KeyValuePair<string, string>[] array, int arrayIndex)
+ {
+ foreach (DictionaryEntry de in values)
+ array [arrayIndex++] = new KeyValuePair<string, string> ((string)de.Key, (string)de.Value);
+ }
+
+ public bool Remove (KeyValuePair<string, string> item)
+ {
+ if (Contains (item)) {
+ Remove (item.Key);
+ return true;
+ } else
+ return false;
+ }
+
+ public int Count {
+ get {
+ return values.Count;
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ return false;
+ }
+ }
+
+ public IEnumerator<KeyValuePair<string, string>> GetEnumerator ()
+ {
+ foreach (DictionaryEntry de in values)
+ yield return new KeyValuePair<string,string> ((string)de.Key, (string)de.Value);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ foreach (DictionaryEntry de in values)
+ yield return new KeyValuePair<string,string> ((string)de.Key, (string)de.Value);
+ }
+ }
+
+ public class SlnProjectCollection: Collection<SlnProject>
+ {
+ public SlnProject GetProject (string id)
+ {
+ return this.FirstOrDefault (s => s.Id == id);
+ }
+
+ public SlnProject GetOrCreateProject (string id)
+ {
+ var p = this.FirstOrDefault (s => s.Id.Equals (id, StringComparison.OrdinalIgnoreCase));
+ if (p == null) {
+ p = new SlnProject { Id = id };
+ Add (p);
+ }
+ return p;
+ }
+ }
+
+ public class SlnSectionCollection: Collection<SlnSection>
+ {
+ public SlnSection GetSection (string id)
+ {
+ return this.FirstOrDefault (s => s.Id == id);
+ }
+
+ public SlnSection GetOrCreateSection (string id, string sectionType)
+ {
+ var sec = this.FirstOrDefault (s => s.Id == id);
+ if (sec == null) {
+ sec = new SlnSection { Id = id };
+ sec.SectionType = sectionType;
+ Add (sec);
+ }
+ return sec;
+ }
+
+ public void RemoveSection (string id)
+ {
+ var s = GetSection (id);
+ if (s != null)
+ Remove (s);
+ }
+ }
+
+ public class SlnPropertySetCollection: Collection<SlnPropertySet>
+ {
+ public SlnPropertySet GetPropertySet (string id, bool ignoreCase = false)
+ {
+ var sc = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
+ return this.FirstOrDefault (s => s.Id.Equals (id, sc));
+ }
+
+ public SlnPropertySet GetOrCreatePropertySet (string id, bool ignoreCase = false)
+ {
+ var ps = GetPropertySet (id, ignoreCase);
+ if (ps == null) {
+ ps = new SlnPropertySet (id);
+ Add (ps);
+ }
+ return ps;
+ }
+ }
+
+ class InvalidSolutionFormatException: Exception
+ {
+ public InvalidSolutionFormatException (int line): base ("Invalid format in line " + line)
+ {
+ }
+
+ public InvalidSolutionFormatException (int line, string msg): base ("Invalid format in line " + line + ": " + msg)
+ {
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFileFormat.cs
index 27baad33c5..f1f4fb5522 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFileFormat.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFileFormat.cs
@@ -27,10 +27,7 @@
//
using System;
-using System.Collections;
using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
@@ -41,11 +38,19 @@ using MonoDevelop.Projects.Extensions;
using MonoDevelop.Core;
using System.Reflection;
using System.Linq;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects.Formats.MSBuild
{
- public class SlnFileFormat
+ class SlnFileFormat
{
+ MSBuildFileFormat format;
+
+ public SlnFileFormat (MSBuildFileFormat format)
+ {
+ this.format = format;
+ }
+
public string GetValidFormatName (object obj, string fileName, MSBuildFileFormat format)
{
return Path.ChangeExtension (fileName, ".sln");
@@ -71,372 +76,299 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return null;
}
- public void WriteFile (string file, object obj, MSBuildFileFormat format, bool saveProjects, IProgressMonitor monitor)
+ public Task WriteFile (string file, object obj, bool saveProjects, ProgressMonitor monitor)
{
- Solution sol = (Solution) obj;
+ return Task.Factory.StartNew (delegate {
+ Solution sol = (Solution)obj;
- string tmpfilename = String.Empty;
- try {
- monitor.BeginTask (GettextCatalog.GetString ("Saving solution: {0}", file), 1);
+ string tmpfilename = String.Empty;
try {
- if (File.Exists (file))
- tmpfilename = Path.GetTempFileName ();
- } catch (IOException) {
- }
+ monitor.BeginTask (GettextCatalog.GetString ("Saving solution: {0}", file), 1);
+ try {
+ if (File.Exists (file))
+ tmpfilename = Path.GetTempFileName ();
+ } catch (IOException) {
+ }
- string baseDir = Path.GetDirectoryName (file);
- if (tmpfilename == String.Empty) {
- WriteFileInternal (file, sol, baseDir, format, saveProjects, monitor);
- } else {
- WriteFileInternal (tmpfilename, sol, baseDir, format, saveProjects, monitor);
- File.Delete (file);
- File.Move (tmpfilename, file);
+ if (tmpfilename == String.Empty) {
+ WriteFileInternal (file, file, sol, saveProjects, monitor);
+ } else {
+ WriteFileInternal (tmpfilename, file, sol, saveProjects, monitor);
+ File.Delete (file);
+ File.Move (tmpfilename, file);
+ }
+ } catch (Exception ex) {
+ monitor.ReportError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
+ LoggingService.LogError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
+
+ if (!String.IsNullOrEmpty (tmpfilename))
+ File.Delete (tmpfilename);
+ throw;
+ } finally {
+ monitor.EndTask ();
}
- } catch (Exception ex) {
- monitor.ReportError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
- LoggingService.LogError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
-
- if (!String.IsNullOrEmpty (tmpfilename))
- File.Delete (tmpfilename);
- throw;
- } finally {
- monitor.EndTask ();
- }
+ });
}
- void WriteFileInternal (string file, Solution solution, string baseDir, MSBuildFileFormat format, bool saveProjects, IProgressMonitor monitor)
+ void WriteFileInternal (string file, string sourceFile, Solution solution, bool saveProjects, ProgressMonitor monitor)
{
- SolutionFolder c = solution.RootFolder;
-
- using (StreamWriter sw = new StreamWriter (file, false, Encoding.UTF8)) {
- sw.NewLine = "\r\n";
-
- SlnData slnData = GetSlnData (c);
- if (slnData == null) {
- // If a non-msbuild project is being converted by just
- // changing the fileformat, then create the SlnData for it
- slnData = new SlnData ();
- c.ExtendedProperties [typeof (SlnFileFormat)] = slnData;
+ string baseDir = Path.GetDirectoryName (sourceFile);
+
+ if (saveProjects) {
+ var items = solution.GetAllSolutionItems ().ToArray ();
+ monitor.BeginTask (items.Length + 1);
+ foreach (var item in items) {
+ try {
+ monitor.BeginStep ();
+ item.SavingSolution = true;
+ item.Save (monitor);
+ } finally {
+ item.SavingSolution = false;
+ }
}
+ } else {
+ monitor.BeginTask (1);
+ monitor.BeginStep ();
+ }
- slnData.UpdateVersion (format);
-
- sw.WriteLine ();
-
- //Write Header
- sw.WriteLine ("Microsoft Visual Studio Solution File, Format Version " + slnData.VersionString);
- sw.WriteLine (slnData.HeaderComment);
- if (slnData.VisualStudioVersion != null)
- sw.WriteLine ("VisualStudioVersion = {0}", slnData.VisualStudioVersion);
- if (slnData.MinimumVisualStudioVersion != null)
- sw.WriteLine ("MinimumVisualStudioVersion = {0}", slnData.MinimumVisualStudioVersion);
-
- //Write the projects
- monitor.BeginTask (GettextCatalog.GetString ("Saving projects"), 1);
- WriteProjects (c, baseDir, sw, saveProjects, monitor);
- monitor.EndTask ();
+ SlnFile sln = new SlnFile ();
+ sln.BaseDirectory = baseDir;
+ if (File.Exists (sourceFile)) {
+ try {
+ sln.Read (sourceFile);
+ } catch (Exception ex) {
+ LoggingService.LogError ("Existing solution can't be updated since it can't be read", ex);
+ }
+ }
- //Write the lines for unknownProjects
- foreach (string l in slnData.UnknownProjects)
- sw.WriteLine (l);
+ sln.FormatVersion = format.SlnVersion;
+ sln.ProductDescription = format.ProductDescription;
- //Write the Globals
- sw.WriteLine ("Global");
+ solution.WriteSolution (monitor, sln);
- //Write SolutionConfigurationPlatforms
- //FIXME: SolutionConfigurations?
- sw.WriteLine ("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
+ sln.Write (file);
+ monitor.EndTask ();
+ }
- foreach (SolutionConfiguration config in solution.Configurations)
- sw.WriteLine ("\t\t{0} = {0}", ToSlnConfigurationId (config));
+ internal void WriteFileInternal (SlnFile sln, Solution solution, ProgressMonitor monitor)
+ {
+ SolutionFolder c = solution.RootFolder;
- sw.WriteLine ("\tEndGlobalSection");
+ // Delete data for projects that have been removed from the solution
+
+ var currentProjects = new HashSet<string> (solution.GetAllItems<SolutionFolderItem> ().Select (it => it.ItemId));
+ var removedProjects = new HashSet<string> ();
+ if (solution.LoadedProjects != null)
+ removedProjects.UnionWith (solution.LoadedProjects.Except (currentProjects));
+ var unknownProjects = new HashSet<string> (sln.Projects.Select (p => p.Id).Except (removedProjects).Except (currentProjects));
+
+ foreach (var p in removedProjects) {
+ var ps = sln.Projects.GetProject (p);
+ if (ps != null)
+ sln.Projects.Remove (ps);
+ var pc = sln.ProjectConfigurationsSection.GetPropertySet (p, true);
+ if (pc != null)
+ sln.ProjectConfigurationsSection.Remove (pc);
+ }
+ var secNested = sln.Sections.GetSection ("NestedProjects");
+ if (secNested != null) {
+ foreach (var np in secNested.Properties.ToArray ()) {
+ if (removedProjects.Contains (np.Key) || removedProjects.Contains (np.Value))
+ secNested.Properties.Remove (np.Key);
+ }
+ }
+ solution.LoadedProjects = currentProjects;
- //Write ProjectConfigurationPlatforms
- sw.WriteLine ("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
+ //Write the projects
+ using (monitor.BeginTask (GettextCatalog.GetString ("Saving projects"), 1)) {
+ monitor.BeginStep ();
+ WriteProjects (c, sln, monitor, unknownProjects);
+ }
- List<string> list = new List<string> ();
- WriteProjectConfigurations (solution, list);
+ //FIXME: SolutionConfigurations?
- list.Sort (StringComparer.Create (CultureInfo.InvariantCulture, true));
- foreach (string s in list)
- sw.WriteLine (s);
+ var pset = sln.SolutionConfigurationsSection;
+ foreach (SolutionConfiguration config in solution.Configurations) {
+ var cid = ToSlnConfigurationId (config);
+ pset.SetValue (cid, cid);
+ }
- //Write lines for projects we couldn't load
- if (slnData.SectionExtras.ContainsKey ("ProjectConfigurationPlatforms")) {
- foreach (string s in slnData.SectionExtras ["ProjectConfigurationPlatforms"])
- sw.WriteLine ("\t\t{0}", s);
- }
+ WriteProjectConfigurations (solution, sln);
- sw.WriteLine ("\tEndGlobalSection");
-
- //Write Nested Projects
- ICollection<SolutionFolder> folders = solution.RootFolder.GetAllItems<SolutionFolder> ();
- if (folders.Count > 1) {
- // If folders ==1, that's the root folder
- sw.WriteLine ("\tGlobalSection(NestedProjects) = preSolution");
- foreach (SolutionFolder folder in folders) {
- if (folder.IsRoot)
- continue;
- WriteNestedProjects (folder, solution.RootFolder, sw);
- }
- sw.WriteLine ("\tEndGlobalSection");
+ //Write Nested Projects
+ ICollection<SolutionFolder> folders = solution.RootFolder.GetAllItems<SolutionFolder> ().ToList ();
+ if (folders.Count > 1) {
+ // If folders ==1, that's the root folder
+ var sec = sln.Sections.GetOrCreateSection ("NestedProjects", "preSolution");
+ foreach (SolutionFolder folder in folders) {
+ if (folder.IsRoot)
+ continue;
+ WriteNestedProjects (folder, solution.RootFolder, sec);
}
-
- //Write custom properties
- MSBuildSerializer ser = new MSBuildSerializer (solution.FileName);
- DataItem data = (DataItem) ser.Serialize (solution, typeof(Solution));
+ // Remove items which don't have a parent folder
+ var toRemove = solution.GetAllItems<SolutionFolderItem> ().Where (it => it.ParentFolder == solution.RootFolder);
+ foreach (var it in toRemove)
+ sec.Properties.Remove (it.ItemId);
+ }
+
+ //Write custom properties
+ MSBuildSerializer ser = new MSBuildSerializer (solution.FileName);
+ DataItem data = (DataItem) ser.Serialize (solution, typeof(Solution));
+ if (data.HasItemData) {
+ var sec = sln.Sections.GetOrCreateSection ("MonoDevelopProperties", "preSolution");
+ WriteDataItem (sec.Properties, data);
+ } else
+ sln.Sections.RemoveSection ("MonoDevelopProperties");
+
+ // Write custom properties for configurations
+ foreach (SolutionConfiguration conf in solution.Configurations) {
+ data = (DataItem) ser.Serialize (conf);
+ string secId = "MonoDevelopProperties." + conf.Id;
if (data.HasItemData) {
- sw.WriteLine ("\tGlobalSection(MonoDevelopProperties) = preSolution");
- WriteDataItem (sw, data);
- sw.WriteLine ("\tEndGlobalSection");
- }
-
- // Write custom properties for configurations
- foreach (SolutionConfiguration conf in solution.Configurations) {
- data = (DataItem) ser.Serialize (conf);
- if (data.HasItemData) {
- sw.WriteLine ("\tGlobalSection(MonoDevelopProperties." + conf.Id + ") = preSolution");
- WriteDataItem (sw, data);
- sw.WriteLine ("\tEndGlobalSection");
- }
- }
-
- //Write 'others'
- if (slnData.GlobalExtra != null) {
- foreach (string s in slnData.GlobalExtra)
- sw.WriteLine (s);
+ var sec = sln.Sections.GetOrCreateSection (secId, "preSolution");
+ WriteDataItem (sec.Properties, data);
+ } else {
+ sln.Sections.RemoveSection (secId);
}
-
- sw.WriteLine ("EndGlobal");
}
}
- void WriteProjects (SolutionFolder folder, string baseDirectory, StreamWriter writer, bool saveProjects, IProgressMonitor monitor)
+ void WriteProjects (SolutionFolder folder, SlnFile sln, ProgressMonitor monitor, HashSet<string> unknownProjects)
{
- monitor.BeginStepTask (GettextCatalog.GetString ("Saving projects"), folder.Items.Count, 1);
- foreach (SolutionItem ce in folder.Items)
+ monitor.BeginTask (folder.Items.Count);
+ foreach (SolutionFolderItem ce in folder.Items)
{
- string[] l = null;
- if (ce is SolutionEntityItem) {
+ monitor.BeginStep ();
+ if (ce is SolutionItem) {
- SolutionEntityItem item = (SolutionEntityItem) ce;
- MSBuildHandler handler = MSBuildProjectService.GetItemHandler (item);
-
- if (saveProjects) {
- try {
- handler.SavingSolution = true;
- item.Save (monitor);
- } finally {
- handler.SavingSolution = false;
- }
- }
+ SolutionItem item = (SolutionItem) ce;
- l = handler.SlnProjectContent;
+ var proj = sln.Projects.GetOrCreateProject (ce.ItemId);
+ proj.TypeGuid = item.TypeGuid;
+ proj.Name = item.Name;
+ proj.FilePath = FileService.NormalizeRelativePath (FileService.AbsoluteToRelativePath (sln.BaseDirectory, item.FileName)).Replace ('/', '\\');
- writer.WriteLine (@"Project(""{0}"") = ""{1}"", ""{2}"", ""{3}""",
- handler.TypeGuid,
- item.Name,
- FileService.NormalizeRelativePath (FileService.AbsoluteToRelativePath (
- baseDirectory, item.FileName)).Replace ('/', '\\'),
- ce.ItemId);
- DataItem data = handler.WriteSlnData ();
+ DataItem data = item.WriteSlnData ();
if (data != null && data.HasItemData) {
- writer.WriteLine ("\tProjectSection(MonoDevelopProperties) = preProject");
- WriteDataItem (writer, data);
- writer.WriteLine ("\tEndProjectSection");
- }
+ var sec = proj.Sections.GetOrCreateSection ("MonoDevelopProperties", "preProject");
+ WriteDataItem (sec.Properties, data);
+ } else
+ proj.Sections.RemoveSection ("MonoDevelopProperties");
+
if (item.ItemDependencies.Count > 0) {
- writer.WriteLine ("\tProjectSection(ProjectDependencies) = postProject");
+ var sec = proj.Sections.GetOrCreateSection ("ProjectDependencies", "postProject");
+ sec.Properties.ClearExcept (unknownProjects);
foreach (var dep in item.ItemDependencies)
- writer.WriteLine ("\t\t{0} = {0}", dep.ItemId);
- if (handler.UnresolvedProjectDependencies != null) {
- foreach (var dep in handler.UnresolvedProjectDependencies)
- writer.WriteLine ("\t\t{0} = {0}", dep);
- }
- writer.WriteLine ("\tEndProjectSection");
- }
+ sec.Properties.SetValue (dep.ItemId, dep.ItemId);
+ } else
+ proj.Sections.RemoveSection ("ProjectDependencies");
} else if (ce is SolutionFolder) {
- //Solution
- SlnData slnData = GetSlnData (ce);
- if (slnData == null) {
- // Solution folder
- slnData = new SlnData ();
- ce.ExtendedProperties [typeof (SlnFileFormat)] = slnData;
- }
+ var proj = sln.Projects.GetOrCreateProject (ce.ItemId);
+ proj.TypeGuid = MSBuildProjectService.FolderTypeGuid;
+ proj.Name = ce.Name;
+ proj.FilePath = ce.Name;
- l = slnData.Extra;
-
- writer.WriteLine (@"Project(""{0}"") = ""{1}"", ""{2}"", ""{3}""",
- MSBuildProjectService.FolderTypeGuid,
- ce.Name,
- ce.Name,
- ce.ItemId);
-
// Folder files
- WriteFolderFiles (writer, (SolutionFolder) ce);
+ WriteFolderFiles (proj, (SolutionFolder) ce);
//Write custom properties
MSBuildSerializer ser = new MSBuildSerializer (folder.ParentSolution.FileName);
DataItem data = (DataItem) ser.Serialize (ce, typeof(SolutionFolder));
if (data.HasItemData) {
- writer.WriteLine ("\tProjectSection(MonoDevelopProperties) = preProject");
- WriteDataItem (writer, data);
- writer.WriteLine ("\tEndProjectSection");
+ var sec = proj.Sections.GetOrCreateSection ("MonoDevelopProperties", "preProject");
+ WriteDataItem (sec.Properties, data);
}
}
-
- if (l != null) {
- foreach (string s in l)
- writer.WriteLine (s);
- }
-
- writer.WriteLine ("EndProject");
if (ce is SolutionFolder)
- WriteProjects (ce as SolutionFolder, baseDirectory, writer, saveProjects, monitor);
- monitor.Step (1);
+ WriteProjects (ce as SolutionFolder, sln, monitor, unknownProjects);
}
monitor.EndTask ();
}
- void WriteFolderFiles (StreamWriter writer, SolutionFolder folder)
+ void WriteFolderFiles (SlnProject proj, SolutionFolder folder)
{
if (folder.Files.Count > 0) {
- writer.WriteLine ("\tProjectSection(SolutionItems) = preProject");
+ var sec = proj.Sections.GetOrCreateSection ("SolutionItems", "preProject");
+ sec.Properties.Clear ();
foreach (FilePath f in folder.Files) {
string relFile = MSBuildProjectService.ToMSBuildPathRelative (folder.ParentSolution.ItemDirectory, f);
- writer.WriteLine ("\t\t" + relFile + " = " + relFile);
+ sec.Properties.SetValue (relFile, relFile);
}
- writer.WriteLine ("\tEndProjectSection");
- }
+ } else
+ proj.Sections.RemoveSection ("SolutionItems");
}
- void WriteProjectConfigurations (Solution sol, List<string> list)
+ void WriteProjectConfigurations (Solution sol, SlnFile sln)
{
- foreach (SolutionConfiguration cc in sol.Configurations) {
+ var col = sln.ProjectConfigurationsSection;
+
+ foreach (var item in sol.GetAllSolutionItems ()) {
+ // Don't save configurations for shared projects
+ if (!item.SupportsConfigurations ())
+ continue;
- foreach (SolutionConfigurationEntry cce in cc.Configurations) {
- SolutionEntityItem p = cce.Item;
+ // <ProjectGuid>...</ProjectGuid> in some Visual Studio generated F# project files
+ // are missing "{"..."}" in their guid. This is not generally a problem since it
+ // is a valid GUID format. However the solution file format requires that these are present.
+ string itemGuid = item.ItemId;
+ if (!itemGuid.StartsWith ("{") && !itemGuid.EndsWith ("}"))
+ itemGuid = "{" + itemGuid + "}";
- // Don't save configurations for shared projects
- if (!p.SupportsBuild () && !(p is UnloadedSolutionItem))
+ var pset = col.GetOrCreatePropertySet (itemGuid, ignoreCase:true);
+ pset.Clear ();
+
+ foreach (SolutionConfiguration cc in sol.Configurations) {
+ var cce = cc.GetEntryForItem (item);
+ if (cce == null)
continue;
-
- // <ProjectGuid>...</ProjectGuid> in some Visual Studio generated F# project files
- // are missing "{"..."}" in their guid. This is not generally a problem since it
- // is a valid GUID format. However the solution file format requires that these are present.
- string itemGuid = p.ItemId;
- if (!itemGuid.StartsWith("{") && !itemGuid.EndsWith("}"))
- itemGuid = "{" + itemGuid + "}";
+ var configId = ToSlnConfigurationId (cc);
+ var itemConfigId = ToSlnConfigurationId (cce.ItemConfiguration);
- list.Add (String.Format (
- "\t\t{0}.{1}.ActiveCfg = {2}", itemGuid, ToSlnConfigurationId (cc), ToSlnConfigurationId (cce.ItemConfiguration)));
+ pset.SetValue (configId + ".ActiveCfg", itemConfigId);
if (cce.Build)
- list.Add (String.Format (
- "\t\t{0}.{1}.Build.0 = {2}", itemGuid, ToSlnConfigurationId (cc), ToSlnConfigurationId (cce.ItemConfiguration)));
-
+ pset.SetValue (configId + ".Build.0", itemConfigId);
+
if (cce.Deploy)
- list.Add (String.Format (
- "\t\t{0}.{1}.Deploy.0 = {2}", itemGuid, ToSlnConfigurationId (cc), ToSlnConfigurationId (cce.ItemConfiguration)));
+ pset.SetValue (configId + ".Deploy.0", itemConfigId);
}
}
-
}
- void WriteNestedProjects (SolutionFolder folder, SolutionFolder root, StreamWriter writer)
+ void WriteNestedProjects (SolutionFolder folder, SolutionFolder root, SlnSection sec)
{
- foreach (SolutionItem ce in folder.Items)
- writer.WriteLine (@"{0}{1} = {2}", "\t\t", ce.ItemId, folder.ItemId);
+ foreach (SolutionFolderItem ce in folder.Items)
+ sec.Properties.SetValue (ce.ItemId, folder.ItemId);
}
- DataItem GetSolutionItemData (List<string> lines)
+ List<string> ReadSolutionItemDependencies (SlnProject proj)
{
- // Find a project section of type MonoDevelopProperties
- int start, end;
- if (!FindSection (lines, "MonoDevelopProperties", true, out start, out end))
- return null;
-
- // Deserialize the object
- DataItem it = ReadDataItem (start, end - start + 1, lines);
-
- // Remove the lines, since they have already been preocessed
- lines.RemoveRange (start, end - start + 1);
- return it;
- }
-
- List<string> ReadSolutionItemDependencies (List<string> lines)
- {
- // Find a project section of type MonoDevelopProperties
- int start, end;
- if (!FindSection (lines, "ProjectDependencies", false, out start, out end))
+ // Find a project section of type ProjectDependencies
+ var sec = proj.Sections.GetSection ("ProjectDependencies");
+ if (sec == null)
return null;
- var ids = new List<string> ();
- for (int n=start + 1; n < end; n++) {
- string line = lines [n];
- int i = line.IndexOf ('=');
- if (i != -1)
- ids.Add (line.Substring (0, i).Trim ());
- }
-
- // Remove the lines, since they have already been preocessed
- lines.RemoveRange (start, end - start + 1);
- return ids;
+ return sec.Properties.Keys.ToList ();
}
- List<string> ReadFolderFiles (List<string> lines)
+ IEnumerable<string> ReadFolderFiles (SlnProject proj)
{
// Find a solution item section of type SolutionItems
+ var sec = proj.Sections.GetSection ("SolutionItems");
+ if (sec == null)
+ return new string[0];
- List<string> list = new List<string> ();
- int start, end;
- if (!FindSection (lines, "SolutionItems", true, out start, out end))
- return list;
-
- for (int n=start + 1; n < end; n++) {
- string file = lines [n];
- int i = file.IndexOf ('=');
- if (i == -1)
- continue;
- file = file.Substring (0, i).Trim (' ','\t');
- if (file.Length > 0)
- list.Add (file);
- }
-
- // Remove the lines, since they have already been preocessed
- lines.RemoveRange (start, end - start + 1);
- return list;
+ return sec.Properties.Keys.ToList ();
}
-
- bool FindSection (List<string> lines, string name, bool preProject, out int start, out int end)
- {
- start = -1;
- end = -1;
- string prePost = preProject ? "preProject" : "postProject";
- var sectionLine = "ProjectSection(" + name + ")=" + prePost;
-
- for (int n=0; n<lines.Count && start == -1; n++) {
- string line = lines [n].Replace ("\t","").Replace (" ", "");
- if (line == sectionLine)
- start = n;
- }
- if (start == -1)
- return false;
-
- for (int n=start+1; n<lines.Count && end == -1; n++) {
- string line = lines [n].Replace ("\t","").Replace (" ", "");
- if (line == "EndProjectSection")
- end = n;
- }
- return end != -1;
- }
-
- void DeserializeSolutionItem (Solution sln, SolutionItem item, List<string> lines)
+ void DeserializeSolutionItem (Solution sln, SolutionFolderItem item, SlnProject proj)
{
// Deserialize the object
- DataItem it = GetSolutionItemData (lines);
+ var sec = proj.Sections.GetSection ("MonoDevelopProperties");
+ if (sec == null)
+ return;
+
+ DataItem it = ReadDataItem (sec);
if (it == null)
return;
@@ -445,14 +377,15 @@ namespace MonoDevelop.Projects.Formats.MSBuild
ser.Deserialize (item, it);
}
- void WriteDataItem (StreamWriter sw, DataItem item)
+ void WriteDataItem (SlnPropertySet pset, DataItem item)
{
+ pset.Clear ();
int id = 0;
foreach (DataNode val in item.ItemData)
- WriteDataNode (sw, "", val, ref id);
+ WriteDataNode (pset, "", val, ref id);
}
- void WriteDataNode (StreamWriter sw, string prefix, DataNode node, ref int id)
+ void WriteDataNode (SlnPropertySet pset, string prefix, DataNode node, ref int id)
{
string name = node.Name;
string newPrefix = prefix.Length > 0 ? prefix + "." + name: name;
@@ -460,15 +393,15 @@ namespace MonoDevelop.Projects.Formats.MSBuild
if (node is DataValue) {
DataValue val = (DataValue) node;
string value = EncodeString (val.Value);
- sw.WriteLine ("\t\t" + newPrefix + " = " + value);
+ pset.SetValue (newPrefix, value);
}
else {
DataItem it = (DataItem) node;
- sw.WriteLine ("\t\t" + newPrefix + " = $" + id);
+ pset.SetValue (newPrefix, "$" + id);
newPrefix = "$" + id;
id ++;
foreach (DataNode cn in it.ItemData)
- WriteDataNode (sw, newPrefix, cn, ref id);
+ WriteDataNode (pset, newPrefix, cn, ref id);
}
}
@@ -533,16 +466,14 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return val;
}
- DataItem ReadDataItem (Section sec, List<string> lines)
- {
- return ReadDataItem (sec.Start, sec.Count, lines);
- }
-
- DataItem ReadDataItem (int start, int count, List<string> lines)
+ DataItem ReadDataItem (SlnSection sec)
{
DataItem it = new DataItem ();
- int lineNum = start + 1;
- int lastLine = start + count - 2;
+
+ var lines = sec.Properties.ToArray ();
+
+ int lineNum = 0;
+ int lastLine = lines.Length - 1;
while (lineNum <= lastLine) {
if (!ReadDataNode (it, lines, lastLine, "", ref lineNum))
lineNum++;
@@ -550,38 +481,26 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return it;
}
- bool ReadDataNode (DataItem item, List<string> lines, int lastLine, string prefix, ref int lineNum)
+ bool ReadDataNode (DataItem item, KeyValuePair<string,string>[] lines, int lastLine, string prefix, ref int lineNum)
{
- string s = lines [lineNum].Trim (' ','\t');
-
- if (s.Length == 0) {
- lineNum++;
- return true;
- }
+ var s = lines [lineNum];
// Check if the line belongs to the current item
if (prefix.Length > 0) {
- if (!s.StartsWith (prefix + "."))
+ if (!s.Key.StartsWith (prefix + "."))
return false;
- s = s.Substring (prefix.Length + 1);
} else {
- if (s.StartsWith ("$"))
+ if (s.Key.StartsWith ("$"))
return false;
}
- int i = s.IndexOf ('=');
- if (i == -1) {
- lineNum++;
- return true;
- }
-
- string name = s.Substring (0, i).Trim (' ','\t');
+ string name = s.Key;
if (name.Length == 0) {
lineNum++;
return true;
}
- string value = s.Substring (i+1).Trim (' ','\t');
+ string value = s.Value;
if (value.StartsWith ("$")) {
// New item
DataItem child = new DataItem ();
@@ -629,7 +548,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
//Reader
- public object ReadFile (string fileName, MSBuildFileFormat format, IProgressMonitor monitor)
+ public async Task<object> ReadFile (string fileName, ProgressMonitor monitor)
{
if (fileName == null || monitor == null)
return null;
@@ -639,10 +558,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild
ProjectExtensionUtil.BeginLoadOperation ();
sol = new Solution ();
monitor.BeginTask (string.Format (GettextCatalog.GetString ("Loading solution: {0}"), fileName), 1);
- var projectLoadMonitor = monitor as IProjectLoadProgressMonitor;
+ var projectLoadMonitor = monitor as ProjectLoadProgressMonitor;
if (projectLoadMonitor != null)
projectLoadMonitor.CurrentSolution = sol;
- LoadSolution (sol, fileName, format, monitor);
+ await Task.Factory.StartNew (() => LoadSolution (sol, fileName, monitor));
} catch (Exception ex) {
monitor.ReportError (GettextCatalog.GetString ("Could not load solution: {0}", fileName), ex);
throw;
@@ -653,129 +572,63 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return sol;
}
- //ExtendedProperties
- // Per config
- // Platform : Eg. Any CPU
- // SolutionConfigurationPlatforms
- //
- SolutionFolder LoadSolution (Solution sol, string fileName, MSBuildFileFormat format, IProgressMonitor monitor)
+ SolutionFolder LoadSolution (Solution sol, string fileName, ProgressMonitor monitor)
{
- string headerComment;
- string version = GetSlnFileVersion (fileName, out headerComment);
-
- ListDictionary globals = null;
- SolutionFolder folder = null;
- SlnData data = null;
- List<Section> projectSections = null;
- List<string> lines = null;
-
FileFormat projectFormat = Services.ProjectService.FileFormats.GetFileFormat (format);
monitor.BeginTask (GettextCatalog.GetString ("Loading solution: {0}", fileName), 1);
- //Parse the .sln file
- using (StreamReader reader = new StreamReader(fileName)) {
- sol.FileName = fileName;
- sol.ConvertToFormat (projectFormat, false);
- folder = sol.RootFolder;
- sol.Version = "0.1"; //FIXME:
- data = new SlnData ();
- folder.ExtendedProperties [typeof (SlnFileFormat)] = data;
- data.VersionString = version;
- data.HeaderComment = headerComment;
-
- string s = null;
- projectSections = new List<Section> ();
- lines = new List<string> ();
- globals = new ListDictionary ();
- //Parse
- while (reader.Peek () >= 0) {
- s = GetNextLine (reader, lines).Trim ();
-
- if (String.Compare (s, "Global", StringComparison.OrdinalIgnoreCase) == 0) {
- ParseGlobal (reader, lines, globals);
- continue;
- }
-
- if (s.StartsWith ("Project", StringComparison.Ordinal)) {
- Section sec = new Section ();
- projectSections.Add (sec);
- sec.Start = lines.Count - 1;
+ var sln = new SlnFile ();
+ sln.Read (fileName);
- int e = ReadUntil ("EndProject", reader, lines);
- sec.Count = (e < 0) ? 1 : (e - sec.Start + 1);
+ sol.FileName = fileName;
+ sol.ConvertToFormat (projectFormat, false);
- continue;
- }
+ sol.ReadSolution (monitor, sln);
+ return sol.RootFolder;
+ }
- if (s.StartsWith ("VisualStudioVersion = ", StringComparison.Ordinal)) {
- Version v;
- if (Version.TryParse (s.Substring ("VisualStudioVersion = ".Length), out v))
- data.VisualStudioVersion = v;
- else
- monitor.Log.WriteLine ("Ignoring unparseable VisualStudioVersion value in sln file");
- }
+ internal void LoadSolution (Solution sol, SlnFile sln, ProgressMonitor monitor)
+ {
+ var version = sln.FormatVersion;
- if (s.StartsWith ("MinimumVisualStudioVersion = ", StringComparison.Ordinal)) {
- Version v;
- if (Version.TryParse (s.Substring ("MinimumVisualStudioVersion = ".Length), out v))
- data.MinimumVisualStudioVersion = v;
- else
- monitor.Log.WriteLine ("Ignoring unparseable MinimumVisualStudioVersion value in sln file");
- }
- }
- }
+ //Parse the .sln file
+ var folder = sol.RootFolder;
+ sol.Version = "0.1"; //FIXME:
- monitor.BeginTask("Loading projects ..", projectSections.Count + 1);
- Dictionary<string, SolutionItem> items = new Dictionary<string, SolutionItem> ();
- List<SolutionItem> sortedList = new List<SolutionItem> ();
- foreach (Section sec in projectSections) {
+ monitor.BeginTask("Loading projects ..", sln.Projects.Count + 1);
+ Dictionary<string, SolutionFolderItem> items = new Dictionary<string, SolutionFolderItem> ();
+ List<SolutionFolderItem> sortedList = new List<SolutionFolderItem> ();
+ foreach (SlnProject sec in sln.Projects) {
monitor.Step (1);
- Match match = ProjectRegex.Match (lines [sec.Start]);
- if (!match.Success) {
- LoggingService.LogDebug (GettextCatalog.GetString (
- "Invalid Project definition on line number #{0} in file '{1}'. Ignoring.",
- sec.Start + 1,
- fileName));
-
- continue;
- }
-
try {
// Valid guid?
- new Guid (match.Groups [1].Value);
+ new Guid (sec.TypeGuid);
} catch (FormatException) {
//Use default guid as projectGuid
LoggingService.LogDebug (GettextCatalog.GetString (
"Invalid Project type guid '{0}' on line #{1}. Ignoring.",
- match.Groups [1].Value,
- sec.Start + 1));
+ sec.Id,
+ sec.Line));
continue;
}
- string projTypeGuid = match.Groups [1].Value.ToUpper ();
- string projectName = match.Groups [2].Value;
- string projectPath = match.Groups [3].Value;
- string projectGuid = match.Groups [4].Value.ToUpper ();
- List<string> projLines;
+ string projTypeGuid = sec.TypeGuid.ToUpper ();
+ string projectName = sec.Name;
+ string projectPath = sec.FilePath;
+ string projectGuid = sec.Id;
if (projTypeGuid == MSBuildProjectService.FolderTypeGuid) {
//Solution folder
SolutionFolder sfolder = new SolutionFolder ();
sfolder.Name = projectName;
- MSBuildProjectService.InitializeItemHandler (sfolder);
- MSBuildProjectService.SetId (sfolder, projectGuid);
+ sfolder.ItemId = projectGuid;
- projLines = lines.GetRange (sec.Start + 1, sec.Count - 2);
- DeserializeSolutionItem (sol, sfolder, projLines);
+ DeserializeSolutionItem (sol, sfolder, sec);
- foreach (string f in ReadFolderFiles (projLines))
- sfolder.Files.Add (MSBuildProjectService.FromMSBuildPath (Path.GetDirectoryName (fileName), f));
+ foreach (string f in ReadFolderFiles (sec))
+ sfolder.Files.Add (MSBuildProjectService.FromMSBuildPath (Path.GetDirectoryName (sol.FileName), f));
- SlnData slnData = new SlnData ();
- slnData.Extra = projLines.ToArray ();
- sfolder.ExtendedProperties [typeof (SlnFileFormat)] = slnData;
-
items.Add (projectGuid, sfolder);
sortedList.Add (sfolder);
@@ -785,42 +638,38 @@ namespace MonoDevelop.Projects.Formats.MSBuild
if (projectPath.StartsWith("http://")) {
monitor.ReportWarning (GettextCatalog.GetString (
"{0}({1}): Projects with non-local source (http://...) not supported. '{2}'.",
- fileName, sec.Start + 1, projectPath));
- data.UnknownProjects.AddRange (lines.GetRange (sec.Start, sec.Count));
+ sol.FileName, sec.Line, projectPath));
continue;
}
- string path = MSBuildProjectService.FromMSBuildPath (Path.GetDirectoryName (fileName), projectPath);
+ string path = MSBuildProjectService.FromMSBuildPath (Path.GetDirectoryName (sol.FileName), projectPath);
if (String.IsNullOrEmpty (path)) {
monitor.ReportWarning (GettextCatalog.GetString (
- "Invalid project path found in {0} : {1}", fileName, projectPath));
+ "Invalid project path found in {0} : {1}", sol.FileName, projectPath));
LoggingService.LogWarning (GettextCatalog.GetString (
- "Invalid project path found in {0} : {1}", fileName, projectPath));
+ "Invalid project path found in {0} : {1}", sol.FileName, projectPath));
continue;
}
projectPath = Path.GetFullPath (path);
- SolutionEntityItem item = null;
+ SolutionItem item = null;
try {
if (sol.IsSolutionItemEnabled (projectPath)) {
- item = ProjectExtensionUtil.LoadSolutionItem (monitor, projectPath, delegate {
+ var t = ProjectExtensionUtil.LoadSolutionItem (monitor, projectPath, delegate {
return MSBuildProjectService.LoadItem (monitor, projectPath, format, projTypeGuid, projectGuid);
});
+ t.Wait ();
+ item = t.Result;
if (item == null) {
throw new UnknownSolutionItemTypeException (projTypeGuid);
}
} else {
- var uitem = new UnloadedSolutionItem () {
+ item = new UnloadedSolutionItem () {
FileName = projectPath
};
- var h = new MSBuildHandler (projTypeGuid, projectGuid) {
- Item = uitem,
- };
- uitem.SetItemHandler (h);
- item = uitem;
}
} catch (Exception e) {
@@ -837,7 +686,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
var relPath = new FilePath (path).ToRelative (sol.BaseDirectory);
if (!string.IsNullOrEmpty (name)) {
var guids = name.Split (';');
- var projectInfo = MSBuildProjectService.GetUnknownProjectTypeInfo (guids, fileName);
+ var projectInfo = MSBuildProjectService.GetUnknownProjectTypeInfo (guids, sol.FileName);
if (projectInfo != null) {
loadAsProject = projectInfo.LoadFiles;
LoggingService.LogWarning (string.Format ("Could not load {0} project '{1}'. {2}", projectInfo.Name, relPath, projectInfo.GetInstructions ()));
@@ -861,218 +710,143 @@ namespace MonoDevelop.Projects.Formats.MSBuild
"Error while trying to load the project '{0}': {1}", projectPath, e.Message));
}
- SolutionEntityItem uitem;
+ SolutionItem uitem;
if (loadAsProject) {
uitem = new UnknownProject () {
FileName = projectPath,
- LoadError = e.Message,
+ UnsupportedProjectMessage = e.Message,
};
} else {
uitem = new UnknownSolutionItem () {
FileName = projectPath,
- LoadError = e.Message,
+ UnsupportedProjectMessage = e.Message,
};
}
-
- var h = new MSBuildHandler (projTypeGuid, projectGuid) {
- Item = uitem,
- };
- uitem.SetItemHandler (h);
item = uitem;
}
- MSBuildHandler handler = (MSBuildHandler) item.ItemHandler;
- projLines = lines.GetRange (sec.Start + 1, sec.Count - 2);
- DataItem it = GetSolutionItemData (projLines);
+ item.UnresolvedProjectDependencies = ReadSolutionItemDependencies (sec);
- handler.UnresolvedProjectDependencies = ReadSolutionItemDependencies (projLines);
- handler.SlnProjectContent = projLines.ToArray ();
- handler.ReadSlnData (it);
+ // Deserialize the object
+ var ssec = sec.Sections.GetSection ("MonoDevelopProperties");
+ if (ssec != null) {
+ DataItem it = ReadDataItem (ssec);
+ item.ReadSlnData (it);
+ }
if (!items.ContainsKey (projectGuid)) {
items.Add (projectGuid, item);
sortedList.Add (item);
- data.ItemsByGuid [projectGuid] = item;
} else {
monitor.ReportError (GettextCatalog.GetString ("Invalid solution file. There are two projects with the same GUID. The project {0} will be ignored.", projectPath), null);
}
}
monitor.EndTask ();
- if (globals != null && globals.Contains ("NestedProjects")) {
- LoadNestedProjects (globals ["NestedProjects"] as Section, lines, items, monitor);
- globals.Remove ("NestedProjects");
- }
+ sol.LoadedProjects = new HashSet<string> (items.Keys);
+
+ var nested = sln.Sections.GetSection ("NestedProjects");
+ if (nested != null)
+ LoadNestedProjects (nested, items, monitor);
// Resolve project dependencies
- foreach (var it in items.OfType<SolutionEntityItem> ()) {
- MSBuildHandler handler = (MSBuildHandler) it.ItemHandler;
- if (handler.UnresolvedProjectDependencies != null) {
- foreach (var id in handler.UnresolvedProjectDependencies.ToArray ()) {
- SolutionItem dep;
- if (items.TryGetValue (id, out dep) && dep is SolutionEntityItem) {
- handler.UnresolvedProjectDependencies.Remove (id);
- it.ItemDependencies.Add ((SolutionEntityItem)dep);
+ foreach (var it in items.Values.OfType<SolutionItem> ()) {
+ if (it.UnresolvedProjectDependencies != null) {
+ foreach (var id in it.UnresolvedProjectDependencies.ToArray ()) {
+ SolutionFolderItem dep;
+ if (items.TryGetValue (id, out dep) && dep is SolutionItem) {
+ it.UnresolvedProjectDependencies.Remove (id);
+ it.ItemDependencies.Add ((SolutionItem)dep);
}
}
- if (handler.UnresolvedProjectDependencies.Count == 0)
- handler.UnresolvedProjectDependencies = null;
+ if (it.UnresolvedProjectDependencies.Count == 0)
+ it.UnresolvedProjectDependencies = null;
}
}
//Add top level folders and projects to the main folder
- foreach (SolutionItem ce in sortedList) {
+ foreach (SolutionFolderItem ce in sortedList) {
if (ce.ParentFolder == null)
folder.Items.Add (ce);
}
//FIXME: This can be just SolutionConfiguration also!
- if (globals != null) {
- if (globals.Contains ("SolutionConfigurationPlatforms")) {
- LoadSolutionConfigurations (globals ["SolutionConfigurationPlatforms"] as Section, lines,
- sol, monitor);
- globals.Remove ("SolutionConfigurationPlatforms");
- }
+ LoadSolutionConfigurations (sln.SolutionConfigurationsSection, sol, monitor);
- if (globals.Contains ("ProjectConfigurationPlatforms")) {
- LoadProjectConfigurationMappings (globals ["ProjectConfigurationPlatforms"] as Section, lines,
- sol, monitor);
- globals.Remove ("ProjectConfigurationPlatforms");
- }
+ LoadProjectConfigurationMappings (sln.ProjectConfigurationsSection, sol, items, monitor);
- if (globals.Contains ("MonoDevelopProperties")) {
- LoadMonoDevelopProperties (globals ["MonoDevelopProperties"] as Section, lines, sol, monitor);
- globals.Remove ("MonoDevelopProperties");
- }
-
- ArrayList toRemove = new ArrayList ();
- foreach (DictionaryEntry e in globals) {
- string name = (string) e.Key;
- if (name.StartsWith ("MonoDevelopProperties.")) {
- int i = name.IndexOf ('.');
- LoadMonoDevelopConfigurationProperties (name.Substring (i+1), (Section)e.Value, lines, sol, monitor);
- toRemove.Add (e.Key);
- }
+ LoadMonoDevelopProperties (sln.Sections.GetSection ("MonoDevelopProperties"), sol, monitor);
+
+ foreach (var e in sln.Sections) {
+ string name = e.Id;
+ if (name.StartsWith ("MonoDevelopProperties.")) {
+ int i = name.IndexOf ('.');
+ LoadMonoDevelopConfigurationProperties (name.Substring (i+1), e, sol, monitor);
}
- foreach (object key in toRemove)
- globals.Remove (key);
}
- //Save the global sections that we dont use
- List<string> globalLines = new List<string> ();
- foreach (Section sec in globals.Values)
- globalLines.InsertRange (globalLines.Count, lines.GetRange (sec.Start, sec.Count));
-
- data.GlobalExtra = globalLines;
monitor.EndTask ();
-
- // When reloading a project, keep the solution data and item id
- sol.SolutionItemAdded += delegate(object sender, SolutionItemChangeEventArgs e) {
- if (e.Reloading) {
- ItemSlnData.TransferData (e.ReplacedItem, e.SolutionItem);
- var ih = e.SolutionItem.ItemHandler as MSBuildHandler;
- if (ih != null)
- ih.ItemId = e.ReplacedItem.ItemId;
- }
- };
-
- return folder;
}
- void ParseGlobal (StreamReader reader, List<string> lines, ListDictionary dict)
+ void LoadProjectConfigurationMappings (SlnPropertySetCollection sets, Solution sln, Dictionary<string, SolutionFolderItem> items, ProgressMonitor monitor)
{
- //Process GlobalSection-s
- while (reader.Peek () >= 0) {
- string s = GetNextLine (reader, lines).Trim ();
- if (s.Length == 0)
- //Skip blank lines
- continue;
-
- Match m = GlobalSectionRegex.Match (s);
- if (!m.Success) {
- if (String.Compare (s, "EndGlobal", true) == 0)
- return;
-
- continue;
- }
-
- Section sec = new Section (m.Groups [1].Value, m.Groups [2].Value, lines.Count - 1, 1);
- dict [sec.Key] = sec;
-
- sec.Count = ReadUntil ("EndGlobalSection", reader, lines) - sec.Start + 1;
- //FIXME: sec.Count == -1 : No EndGlobalSection found, ignore entry?
- }
- }
-
- void LoadProjectConfigurationMappings (Section sec, List<string> lines, Solution sln, IProgressMonitor monitor)
- {
- if (sec == null || String.Compare (sec.Val, "postSolution", true) != 0)
+ if (sets == null)
return;
Dictionary<string, SolutionConfigurationEntry> cache = new Dictionary<string, SolutionConfigurationEntry> ();
Dictionary<string, string> ignoredProjects = new Dictionary<string, string> ();
- SlnData slnData = GetSlnData (sln.RootFolder);
-
- List<string> extras = new List<string> ();
- for (int i = 0; i < sec.Count - 2; i ++) {
- int lineNum = i + sec.Start + 1;
- string s = lines [lineNum].Trim ();
- extras.Add (s);
-
- //Format:
- // {projectGuid}.SolutionConfigName|SolutionPlatform.ActiveCfg = ProjConfigName|ProjPlatform
- // {projectGuid}.SolutionConfigName|SolutionPlatform.Build.0 = ProjConfigName|ProjPlatform
- // {projectGuid}.SolutionConfigName|SolutionPlatform.Deploy.0 = ProjConfigName|ProjPlatform
+ foreach (var pset in sets) {
+
+ var projGuid = pset.Id;
+
+ if (!items.ContainsKey (projGuid)) {
+ if (ignoredProjects.ContainsKey (projGuid))
+ // already warned
+ continue;
- string [] parts = s.Split (new char [] {'='}, 2);
- if (parts.Length < 2) {
- LoggingService.LogDebug ("{0} ({1}) : Invalid format. Ignoring", sln.FileName, lineNum + 1);
+ LoggingService.LogWarning (GettextCatalog.GetString ("{0} ({1}) : Project with guid = '{2}' not found or not loaded. Ignoring",
+ sln.FileName, pset.Line + 1, projGuid));
+ ignoredProjects [projGuid] = projGuid;
continue;
}
- string action;
- string projConfig = parts [1].Trim ();
-
- string left = parts [0].Trim ();
- if (left.EndsWith (".ActiveCfg")) {
- action = "ActiveCfg";
- left = left.Substring (0, left.Length - 10);
- } else if (left.EndsWith (".Build.0")) {
- action = "Build.0";
- left = left.Substring (0, left.Length - 8);
- } else if (left.EndsWith (".Deploy.0")) {
- action = "Deploy.0";
- left = left.Substring (0, left.Length - 9);
- } else {
- LoggingService.LogWarning (GettextCatalog.GetString ("{0} ({1}) : Unknown action. Only ActiveCfg, Build.0 and Deploy.0 supported.",
- sln.FileName, lineNum + 1));
+ SolutionFolderItem it;
+ if (!items.TryGetValue (projGuid, out it))
continue;
- }
- string [] t = left.Split (new char [] {'.'}, 2);
- if (t.Length < 2) {
- LoggingService.LogDebug ("{0} ({1}) : Invalid format of the left side. Ignoring",
- sln.FileName, lineNum + 1);
+ SolutionItem item = it as SolutionItem;
+
+ if (item == null || !item.SupportsConfigurations ())
continue;
- }
- string projGuid = t [0].ToUpper ();
- string slnConfig = t [1];
+ //Format:
+ // {projectGuid}.SolutionConfigName|SolutionPlatform.ActiveCfg = ProjConfigName|ProjPlatform
+ // {projectGuid}.SolutionConfigName|SolutionPlatform.Build.0 = ProjConfigName|ProjPlatform
+ // {projectGuid}.SolutionConfigName|SolutionPlatform.Deploy.0 = ProjConfigName|ProjPlatform
- if (!slnData.ItemsByGuid.ContainsKey (projGuid)) {
- if (ignoredProjects.ContainsKey (projGuid))
- // already warned
+ foreach (var prop in pset) {
+ string action;
+ string projConfig = prop.Value;
+
+ string left = prop.Key;
+ if (left.EndsWith (".ActiveCfg")) {
+ action = "ActiveCfg";
+ left = left.Substring (0, left.Length - 10);
+ } else if (left.EndsWith (".Build.0")) {
+ action = "Build.0";
+ left = left.Substring (0, left.Length - 8);
+ } else if (left.EndsWith (".Deploy.0")) {
+ action = "Deploy.0";
+ left = left.Substring (0, left.Length - 9);
+ } else {
+ LoggingService.LogWarning (GettextCatalog.GetString ("{0} ({1}) : Unknown action. Only ActiveCfg, Build.0 and Deploy.0 supported.",
+ sln.FileName, pset.Line));
continue;
+ }
- LoggingService.LogWarning (GettextCatalog.GetString ("{0} ({1}) : Project with guid = '{2}' not found or not loaded. Ignoring",
- sln.FileName, lineNum + 1, projGuid));
- ignoredProjects [projGuid] = projGuid;
- continue;
- }
+ string slnConfig = left;
- SolutionEntityItem item;
- if (slnData.ItemsByGuid.TryGetValue (projGuid, out item) && (item.SupportsBuild () || item is UnloadedSolutionItem)) {
string key = projGuid + "." + slnConfig;
SolutionConfigurationEntry combineConfigEntry = null;
if (cache.ContainsKey (key)) {
@@ -1092,6 +866,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
* if Build (true/false) for the project will
* will depend on presence/absence of Build.0 entry
*/
+
if (action == "ActiveCfg") {
combineConfigEntry.ItemConfiguration = FromSlnConfigurationId (projConfig);
} else if (action == "Build.0") {
@@ -1100,15 +875,12 @@ namespace MonoDevelop.Projects.Formats.MSBuild
combineConfigEntry.Deploy = true;
}
}
- extras.RemoveAt (extras.Count - 1);
}
-
- slnData.SectionExtras ["ProjectConfigurationPlatforms"] = extras;
}
/* Gets the CombineConfigurationEntry corresponding to the @entry in its parentCombine's
* CombineConfiguration. Creates the required bits if not present */
- SolutionConfigurationEntry GetConfigEntry (Solution sol, SolutionEntityItem item, string configName)
+ SolutionConfigurationEntry GetConfigEntry (Solution sol, SolutionItem item, string configName)
{
configName = FromSlnConfigurationId (configName);
@@ -1124,21 +896,13 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return solutionConfig.AddItem (item);
}
- void LoadSolutionConfigurations (Section sec, List<string> lines, Solution solution, IProgressMonitor monitor)
+ void LoadSolutionConfigurations (SlnPropertySet sec, Solution solution, ProgressMonitor monitor)
{
- if (sec == null || String.Compare (sec.Val, "preSolution", true) != 0)
+ if (sec == null)
return;
- for (int i = 0; i < sec.Count - 2; i ++) {
- //FIXME: expects both key and val to be on the same line
- int lineNum = i + sec.Start + 1;
- string s = lines [lineNum].Trim ();
- if (s.Length == 0)
- //Skip blank lines
- continue;
+ foreach (var pair in sec) {
- KeyValuePair<string, string> pair = SplitKeyValue (s);
-
string configId = FromSlnConfigurationId (pair.Key);
SolutionConfiguration config = solution.Configurations [configId];
@@ -1154,37 +918,37 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return new SolutionConfiguration (fullId);
}
- void LoadMonoDevelopProperties (Section sec, List<string> lines, Solution sln, IProgressMonitor monitor)
+ void LoadMonoDevelopProperties (SlnSection sec, Solution sln, ProgressMonitor monitor)
{
- DataItem it = ReadDataItem (sec, lines);
+ if (sec == null)
+ return;
+ DataItem it = ReadDataItem (sec);
MSBuildSerializer ser = new MSBuildSerializer (sln.FileName);
ser.SerializationContext.BaseFile = sln.FileName;
ser.Deserialize (sln, it);
}
- void LoadMonoDevelopConfigurationProperties (string configName, Section sec, List<string> lines, Solution sln, IProgressMonitor monitor)
+ void LoadMonoDevelopConfigurationProperties (string configName, SlnSection sec, Solution sln, ProgressMonitor monitor)
{
SolutionConfiguration config = sln.Configurations [configName];
if (config == null)
return;
- DataItem it = ReadDataItem (sec, lines);
+ DataItem it = ReadDataItem (sec);
MSBuildSerializer ser = new MSBuildSerializer (sln.FileName);
ser.Deserialize (config, it);
}
- void LoadNestedProjects (Section sec, List<string> lines,
- IDictionary<string, SolutionItem> entries, IProgressMonitor monitor)
+ void LoadNestedProjects (SlnSection sec, IDictionary<string, SolutionFolderItem> entries, ProgressMonitor monitor)
{
- if (sec == null || String.Compare (sec.Val, "preSolution", true) != 0)
+ if (sec == null || String.Compare (sec.SectionType, "preSolution", StringComparison.OrdinalIgnoreCase) != 0)
return;
- for (int i = 0; i < sec.Count - 2; i ++) {
+ foreach (var kvp in sec.Properties) {
// Guids should be upper case for VS compatibility
- KeyValuePair<string, string> pair = SplitKeyValue (lines [i + sec.Start + 1].Trim ());
- pair = new KeyValuePair<string, string> (pair.Key.ToUpper (), pair.Value.ToUpper ());
+ var pair = new KeyValuePair<string, string> (kvp.Key.ToUpper (), kvp.Value.ToUpper ());
- SolutionItem folderItem;
- SolutionItem item;
+ SolutionFolderItem folderItem;
+ SolutionFolderItem item;
if (!entries.TryGetValue (pair.Value, out folderItem)) {
//Container not found
@@ -1232,17 +996,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
- KeyValuePair<string, string> SplitKeyValue (string s)
- {
- string [] pair = s.Split (new char [] {'='}, 2);
- string key = pair [0].Trim ();
- string val = String.Empty;
- if (pair.Length == 2)
- val = pair [1].Trim ();
-
- return new KeyValuePair<string, string> (key, val);
- }
-
// Utility function to determine the sln file version
string GetSlnFileVersion(string strInSlnFile, out string headerComment)
{
@@ -1276,32 +1029,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return strVersion;
}
- static SlnData GetSlnData (SolutionItem c)
- {
- if (c.ExtendedProperties.Contains (typeof (SlnFileFormat)))
- return c.ExtendedProperties [typeof (SlnFileFormat)] as SlnData;
- return null;
- }
-
- // static regexes
- static Regex projectRegex = null;
- internal static Regex ProjectRegex {
- get {
- if (projectRegex == null)
- projectRegex = new Regex(@"Project\(""(\{[^}]*\})""\) = ""(.*)"", ""(.*)"", ""(\{[^{]*\})""");
- return projectRegex;
- }
- }
-
- static Regex globalSectionRegex = null;
- static Regex GlobalSectionRegex {
- get {
- if (globalSectionRegex == null)
- globalSectionRegex = new Regex (@"GlobalSection\s*\(([^)]*)\)\s*=\s*(\w*)");
- return globalSectionRegex;
- }
- }
-
static Regex slnVersionRegex = null;
internal static Regex SlnVersionRegex {
get {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/UnknownSolutionItemTypeException.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/UnknownSolutionItemTypeException.cs
new file mode 100644
index 0000000000..ce2af4ae34
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/UnknownSolutionItemTypeException.cs
@@ -0,0 +1,64 @@
+//
+// UnknownSolutionItemTypeException.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Xml;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using MonoDevelop.Core;
+using MonoDevelop.Projects;
+using MonoDevelop.Core.Serialization;
+using MonoDevelop.Core.Assemblies;
+using MonoDevelop.Projects.Formats.MD1;
+using MonoDevelop.Projects.Extensions;
+using Mono.Addins;
+using System.Linq;
+using MonoDevelop.Core.Instrumentation;
+using MonoDevelop.Core.ProgressMonitoring;
+using System.Threading.Tasks;
+
+namespace MonoDevelop.Projects.Formats.MSBuild
+{
+
+ class UnknownSolutionItemTypeException : InvalidOperationException
+ {
+ public UnknownSolutionItemTypeException ()
+ : base ("Unknown solution item type")
+ {
+ }
+
+ public UnknownSolutionItemTypeException (string name)
+ : base ("Unknown solution item type: " + name)
+ {
+ this.TypeName = name;
+ }
+
+ public string TypeName { get; private set; }
+ }
+
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/DotNetNamingPolicy.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/DotNetNamingPolicy.cs
index 882004de7c..045e042aa3 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/DotNetNamingPolicy.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/DotNetNamingPolicy.cs
@@ -62,10 +62,10 @@ namespace MonoDevelop.Projects.Policies
internal static ResourceNamePolicy GetDefaultResourceNamePolicy (object ob)
{
FileFormat format = null;
- if (ob is SolutionEntityItem)
- format = ((SolutionEntityItem)ob).FileFormat;
- else if (ob is SolutionItem)
- format = ((SolutionItem)ob).ParentSolution.FileFormat;
+ if (ob is SolutionItem)
+ format = ((SolutionItem)ob).FileFormat;
+ else if (ob is SolutionFolderItem)
+ format = ((SolutionFolderItem)ob).ParentSolution.FileFormat;
else if (ob is Solution)
format = ((Solution)ob).FileFormat;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyBag.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyBag.cs
index 074bcc8d0d..4d8ce0d6be 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyBag.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyBag.cs
@@ -42,7 +42,7 @@ namespace MonoDevelop.Projects.Policies
[DataItem ("Policies")]
public class PolicyBag: PolicyContainer, ICustomDataItem
{
- public PolicyBag (SolutionItem owner)
+ public PolicyBag (SolutionFolderItem owner)
{
this.Owner = owner;
}
@@ -51,7 +51,7 @@ namespace MonoDevelop.Projects.Policies
{
}
- public SolutionItem Owner { get; internal set; }
+ public SolutionFolderItem Owner { get; internal set; }
public override bool IsRoot {
get { return Owner == null || Owner.ParentFolder == null; }
@@ -107,7 +107,7 @@ namespace MonoDevelop.Projects.Policies
{
SolutionFolder solFol = Owner as SolutionFolder;
if (solFol != null)
- foreach (SolutionItem item in solFol.Items)
+ foreach (SolutionFolderItem item in solFol.Items)
if (!item.Policies.DirectHas (args.PolicyType, args.Scope))
item.Policies.OnPolicyChanged (args.PolicyType, args.Scope);
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs
index 2a98dae3cb..f3fd6487ff 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProject.cs
@@ -1,4 +1,4 @@
-//
+//
// SharedProject.cs
//
// Author:
@@ -31,35 +31,130 @@ using MonoDevelop.Core;
using System.IO;
using System.Xml;
using MonoDevelop.Projects.Policies;
+using System.Threading.Tasks;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects.SharedAssetsProjects
{
+ [RegisterProjectType ("{D954291E-2A0B-460D-934E-DC6B0785DB48}", Extension="shproj", Alias="SharedAssetsProject")]
public class SharedAssetsProject: Project, IDotNetFileContainer
{
Solution currentSolution;
IDotNetLanguageBinding languageBinding;
string languageName;
+ string projitemsFile;
public SharedAssetsProject ()
{
+ Initialize (this);
}
- public SharedAssetsProject (string language)
+ public SharedAssetsProject (string language): this ()
{
languageName = language;
}
- public SharedAssetsProject (ProjectCreateInformation projectCreateInfo, XmlElement projectOptions)
+ public SharedAssetsProject (ProjectCreateInformation projectCreateInfo, XmlElement projectOptions): this ()
{
languageName = projectOptions.GetAttribute ("language");
DefaultNamespace = projectCreateInfo.ProjectName;
}
- internal protected override List<FilePath> OnGetItemFiles (bool includeReferencedFiles)
+ protected override void OnReadProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ base.OnReadProject (monitor, msproject);
+
+ var doc = msproject.Document;
+ projitemsFile = null;
+ foreach (var no in doc.DocumentElement.ChildNodes) {
+ var im = no as XmlElement;
+ if (im != null && im.LocalName == "Import" && im.GetAttribute ("Label") == "Shared") {
+ projitemsFile = im.GetAttribute ("Project");
+ break;
+ }
+ }
+ if (projitemsFile == null)
+ return;
+
+ // TODO: load the type from msbuild
+ LanguageName = "C#";
+
+ projitemsFile = Path.Combine (Path.GetDirectoryName (msproject.FileName), projitemsFile);
+
+ MSBuildProject p = new MSBuildProject ();
+ p.Load (projitemsFile);
+
+ var cp = p.PropertyGroups.FirstOrDefault (g => g.Label == "Configuration");
+ if (cp != null)
+ DefaultNamespace = cp.GetValue ("Import_RootNamespace");
+
+ LoadProjectItems (p, ProjectItemFlags.None);
+ }
+
+ protected override void OnWriteProject (ProgressMonitor monitor, MonoDevelop.Projects.Formats.MSBuild.MSBuildProject msproject)
+ {
+ base.OnWriteProject (monitor, msproject);
+
+ MSBuildProject projitemsProject = new MSBuildProject ();
+
+ var newProject = FileName == null || !File.Exists (FileName);
+ if (newProject) {
+ var grp = msproject.GetGlobalPropertyGroup ();
+ if (grp == null)
+ grp = msproject.AddNewPropertyGroup (false);
+ grp.SetValue ("ProjectGuid", ItemId, preserveExistingCase:true);
+ var import = msproject.AddNewImport (@"$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props");
+ import.Condition = @"Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')";
+ msproject.AddNewImport (@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props");
+ msproject.AddNewImport (@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props");
+ import = msproject.AddNewImport (Path.ChangeExtension (FileName.FileName, ".projitems"));
+ import.Label = "Shared";
+ msproject.AddNewImport (@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets");
+ } else {
+ msproject.Load (FileName);
+ }
+
+ // having no ToolsVersion is equivalent to 2.0, roundtrip that correctly
+ if (ToolsVersion != "2.0")
+ msproject.ToolsVersion = ToolsVersion;
+ else if (string.IsNullOrEmpty (msproject.ToolsVersion))
+ msproject.ToolsVersion = null;
+ else
+ msproject.ToolsVersion = "2.0";
+
+ if (projitemsFile == null)
+ projitemsFile = Path.ChangeExtension (FileName, ".projitems");
+ if (File.Exists (projitemsFile)) {
+ projitemsProject.Load (projitemsFile);
+ } else {
+ IMSBuildPropertySet grp = projitemsProject.AddNewPropertyGroup (true);
+ grp.SetValue ("MSBuildAllProjects", "$(MSBuildAllProjects);$(MSBuildThisFileFullPath)");
+ grp.SetValue ("HasSharedItems", true);
+ grp.SetValue ("SharedGUID", ItemId, preserveExistingCase:true);
+ }
+
+ IMSBuildPropertySet configGrp = projitemsProject.PropertyGroups.FirstOrDefault (g => g.Label == "Configuration");
+ if (configGrp == null) {
+ configGrp = projitemsProject.AddNewPropertyGroup (true);
+ configGrp.Label = "Configuration";
+ }
+ configGrp.SetValue ("Import_RootNamespace", DefaultNamespace);
+
+ SaveProjectItems (monitor, new MSBuildFileFormatVS12 (), projitemsProject, "$(MSBuildThisFileDirectory)");
+
+ // Remove all items of this project, since items are saved in the projitems file
+
+ foreach (var it in msproject.GetAllItems ().ToArray ())
+ msproject.RemoveItem (it);
+
+ projitemsProject.Save (projitemsFile);
+ }
+
+ protected override IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
{
- var list = base.OnGetItemFiles (includeReferencedFiles);
+ var list = base.OnGetItemFiles (includeReferencedFiles).ToList ();
if (!string.IsNullOrEmpty (FileName))
- list.Add (FileName.ChangeExtension (".projitems"));
+ list.Add (ProjItemsPath);
return list;
}
@@ -70,10 +165,19 @@ namespace MonoDevelop.Projects.SharedAssetsProjects
public string DefaultNamespace { get; set; }
- public override IEnumerable<string> GetProjectTypes ()
+ public FilePath ProjItemsPath {
+ get {
+ return projitemsFile != null ? (FilePath) projitemsFile : FileName.ChangeExtension (".projitems");
+ }
+ set {
+ projitemsFile = value;
+ }
+ }
+
+ protected override void OnGetProjectTypes (HashSet<string> types)
{
- yield return "SharedAssets";
- yield return "DotNet";
+ types.Add ("SharedAssets");
+ types.Add ("DotNet");
}
public override string[] SupportedLanguages {
@@ -95,17 +199,22 @@ namespace MonoDevelop.Projects.SharedAssetsProjects
return LanguageBinding.IsSourceCodeFile (fileName);
}
- protected override BuildResult OnBuild (MonoDevelop.Core.IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected override Task<BuildResult> OnBuild (MonoDevelop.Core.ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Task.FromResult (BuildResult.Success);
+ }
+
+ protected override bool OnGetSupportsTarget (string target)
{
- return new BuildResult ();
+ return false;
}
- internal protected override bool OnGetSupportsTarget (string target)
+ protected override bool OnGetSupportsExecute ()
{
return false;
}
- internal protected override bool OnGetSupportsExecute ()
+ protected override bool OnGetSupportsBuild ()
{
return false;
}
@@ -143,7 +252,7 @@ namespace MonoDevelop.Projects.SharedAssetsProjects
// Maybe there is a project that is already referencing this one. It may happen when creating a solution
// from a template
- foreach (var p in ParentSolution.GetAllSolutionItems<DotNetProject> ())
+ foreach (var p in ParentSolution.GetAllItems<DotNetProject> ())
ProcessProject (p);
}
@@ -191,6 +300,14 @@ namespace MonoDevelop.Projects.SharedAssetsProjects
void ProcessProject (DotNetProject p)
{
+ // When the projitems file name doesn't match the shproj file name, the reference we add to the referencing projects
+ // uses the projitems name, not the shproj name. Here we detect such case and re-add the references using the correct name
+ var referencesToFix = p.References.Where (r => r.GetItemsProjectPath () == ProjItemsPath && r.Reference != Name).ToList ();
+ foreach (var r in referencesToFix) {
+ p.References.Remove (r);
+ p.References.Add (new ProjectReference (this));
+ }
+
foreach (var pref in p.References.Where (r => r.ReferenceType == ReferenceType.Project && r.Reference == Name))
ProcessNewReference (pref);
}
@@ -198,7 +315,7 @@ namespace MonoDevelop.Projects.SharedAssetsProjects
void ProcessNewReference (ProjectReference pref)
{
pref.Flags = ProjectItemFlags.DontPersist;
- pref.SetItemsProjectPath (Path.ChangeExtension (FileName, ".projitems"));
+ pref.SetItemsProjectPath (ProjItemsPath);
foreach (var f in Files) {
if (pref.OwnerProject.Files.GetFile (f.FilePath) == null) {
var cf = (ProjectFile)f.Clone ();
@@ -268,7 +385,7 @@ namespace MonoDevelop.Projects.SharedAssetsProjects
if (ParentSolution == null)
return new DotNetProject[0];
- return ParentSolution.GetAllSolutionItems<DotNetProject> ().Where (p => p.References.Any (r => r.GetItemsProjectPath () != null));
+ return ParentSolution.GetAllItems<DotNetProject> ().Where (p => p.References.Any (r => r.GetItemsProjectPath () != null));
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildExtension.cs
index 1da660c7a1..645d7b282a 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildExtension.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildExtension.cs
@@ -32,53 +32,45 @@ using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects.SharedAssetsProjects
{
- class SharedAssetsProjectMSBuildExtension: MSBuildExtension
+ [RegisterProjectModelExtension]
+ class SharedAssetsProjectMSBuildExtension: DotNetProjectExtension
{
- public override void LoadProject (IProgressMonitor monitor, SolutionEntityItem item, MSBuildProject msproject)
+ internal protected override void OnReadProject (ProgressMonitor monitor, MSBuildProject msproject)
{
- base.LoadProject (monitor, item, msproject);
-
- var dnp = item as DotNetProject;
- if (dnp == null)
- return;
+ base.OnReadProject (monitor, msproject);
// Convert .projitems imports into project references
foreach (var sp in msproject.Imports.Where (im => im.Label == "Shared" && im.Project.EndsWith (".projitems"))) {
var projitemsFile = sp.Project;
if (!string.IsNullOrEmpty (projitemsFile)) {
- projitemsFile = MSBuildProjectService.FromMSBuildPath (item.ItemDirectory, projitemsFile);
+ projitemsFile = MSBuildProjectService.FromMSBuildPath (Project.ItemDirectory, projitemsFile);
projitemsFile = Path.Combine (Path.GetDirectoryName (msproject.FileName), projitemsFile);
if (File.Exists (projitemsFile)) {
- MSBuildSerializer iser = Handler.CreateSerializer ();
- iser.SerializationContext.BaseFile = projitemsFile;
- iser.SerializationContext.ProgressMonitor = monitor;
MSBuildProject p = new MSBuildProject ();
p.Load (projitemsFile);
- Handler.LoadProjectItems (p, iser, ProjectItemFlags.Hidden | ProjectItemFlags.DontPersist);
+ Project.LoadProjectItems (p, ProjectItemFlags.Hidden | ProjectItemFlags.DontPersist);
var r = new ProjectReference (ReferenceType.Project, Path.GetFileNameWithoutExtension (projitemsFile));
r.Flags = ProjectItemFlags.DontPersist;
r.SetItemsProjectPath (projitemsFile);
- dnp.References.Add (r);
+ Project.References.Add (r);
}
}
}
}
- public override void SaveProject (IProgressMonitor monitor, SolutionEntityItem item, MSBuildProject project)
+ internal protected override void OnWriteProject (ProgressMonitor monitor, MSBuildProject project)
{
- base.SaveProject (monitor, item, project);
- var dnp = item as DotNetProject;
- if (dnp == null)
- return;
+ base.OnWriteProject (monitor, project);
+
HashSet<string> validProjitems = new HashSet<string> ();
- foreach (var r in dnp.References.Where (rp => rp.ReferenceType == ReferenceType.Project)) {
+ foreach (var r in Project.References.Where (rp => rp.ReferenceType == ReferenceType.Project)) {
var ip = r.GetItemsProjectPath ();
if (!string.IsNullOrEmpty (ip)) {
- ip = MSBuildProjectService.ToMSBuildPath (item.ItemDirectory, ip);
+ ip = MSBuildProjectService.ToMSBuildPath (Project.ItemDirectory, ip);
validProjitems.Add (ip);
if (!project.Imports.Any (im => im.Project == ip)) {
- var im = project.AddNewImport (ip, project.Imports.FirstOrDefault (i => i.Label != "Shared"));
+ var im = project.AddNewImport (ip, beforeImport:project.Imports.FirstOrDefault (i => i.Label != "Shared"));
im.Label = "Shared";
im.Condition = "Exists('" + ip + "')";
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildHandler.cs
deleted file mode 100644
index d64df4f8e0..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectMSBuildHandler.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-//
-// SharedProjectMSBuildHandler.cs
-//
-// Author:
-// Lluis Sanchez <lluis@xamarin.com>
-//
-// Copyright (c) 2014 Xamarin Inc
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-using System.Linq;
-using System.Xml;
-using System.IO;
-using MonoDevelop.Core;
-using System.Collections.Generic;
-using MonoDevelop.Projects.Formats.MSBuild;
-
-namespace MonoDevelop.Projects.SharedAssetsProjects
-{
- class SharedAssetsProjectMSBuildHandler: MSBuildProjectHandler
- {
- string projitemsFile;
-
- public SharedAssetsProjectMSBuildHandler ()
- {
- }
-
- protected override void LoadProject (IProgressMonitor monitor, MSBuildProject msproject)
- {
- var doc = msproject.Document;
- projitemsFile = null;
- foreach (var no in doc.DocumentElement.ChildNodes) {
- var im = no as XmlElement;
- if (im != null && im.LocalName == "Import" && im.GetAttribute ("Label") == "Shared") {
- projitemsFile = im.GetAttribute ("Project");
- break;
- }
- }
- if (projitemsFile == null)
- return;
-
- // TODO: load the type from msbuild
- ((SharedAssetsProject)EntityItem).LanguageName = "C#";
-
- projitemsFile = Path.Combine (Path.GetDirectoryName (msproject.FileName), projitemsFile);
-
- MSBuildProject p = new MSBuildProject ();
- p.Load (projitemsFile);
-
- MSBuildSerializer ser = CreateSerializer ();
- ser.SerializationContext.BaseFile = EntityItem.FileName;
- ser.SerializationContext.ProgressMonitor = monitor;
-
- Item.SetItemHandler (this);
-
- var cp = p.PropertyGroups.FirstOrDefault (g => g.Label == "Configuration");
- if (cp != null)
- ((SharedAssetsProject)EntityItem).DefaultNamespace = cp.GetPropertyValue ("Import_RootNamespace");
-
- LoadProjectItems (p, ser, ProjectItemFlags.None);
- }
-
- protected override MSBuildProject SaveProject (IProgressMonitor monitor)
- {
- MSBuildSerializer ser = CreateSerializer ();
- ser.SerializationContext.BaseFile = EntityItem.FileName;
- ser.SerializationContext.ProgressMonitor = monitor;
-
- MSBuildProject projitemsProject = new MSBuildProject ();
- MSBuildProject msproject = new MSBuildProject ();
-
- var newProject = EntityItem.FileName == null || !File.Exists (EntityItem.FileName);
- if (newProject) {
- var grp = msproject.GetGlobalPropertyGroup ();
- if (grp == null)
- grp = msproject.AddNewPropertyGroup (false);
- grp.SetPropertyValue ("ProjectGuid", EntityItem.ItemId, false);
- var import = msproject.AddNewImport (@"$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props");
- import.Condition = @"Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')";
- msproject.AddNewImport (@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props");
- msproject.AddNewImport (@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props");
- import = msproject.AddNewImport (Path.ChangeExtension (EntityItem.FileName.FileName, ".projitems"));
- import.Label = "Shared";
- msproject.AddNewImport (@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets");
- } else {
- msproject.Load (EntityItem.FileName);
- }
-
- // having no ToolsVersion is equivalent to 2.0, roundtrip that correctly
- if (ToolsVersion != "2.0")
- msproject.ToolsVersion = ToolsVersion;
- else if (string.IsNullOrEmpty (msproject.ToolsVersion))
- msproject.ToolsVersion = null;
- else
- msproject.ToolsVersion = "2.0";
-
- if (projitemsFile == null)
- projitemsFile = Path.ChangeExtension (EntityItem.FileName, ".projitems");
- if (File.Exists (projitemsFile)) {
- projitemsProject.Load (projitemsFile);
- } else {
- var grp = projitemsProject.AddNewPropertyGroup (true);
- grp.SetPropertyValue ("MSBuildAllProjects", "$(MSBuildAllProjects);$(MSBuildThisFileFullPath)", false);
- grp.SetPropertyValue ("HasSharedItems", "true", false);
- grp.SetPropertyValue ("SharedGUID", EntityItem.ItemId, false);
- }
-
- var configGrp = projitemsProject.PropertyGroups.FirstOrDefault (g => g.Label == "Configuration");
- if (configGrp == null) {
- configGrp = projitemsProject.AddNewPropertyGroup (true);
- configGrp.Label = "Configuration";
- }
- configGrp.SetPropertyValue ("Import_RootNamespace", ((SharedAssetsProject)EntityItem).DefaultNamespace, false);
-
- SaveProjectItems (monitor, new MSBuildFileFormatVS12 (), ser, projitemsProject, "$(MSBuildThisFileDirectory)");
-
- projitemsProject.Save (projitemsFile);
-
- return msproject;
- }
- }
-}
-
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextEncoding.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextEncoding.cs
index b1126af426..464366de6a 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextEncoding.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextEncoding.cs
@@ -121,7 +121,7 @@ namespace MonoDevelop.Projects.Text
PropertyService.SaveProperties ();
}
}
-
+
public static TextEncoding GetEncoding (string id)
{
foreach (TextEncoding e in SupportedEncodings) {
@@ -130,6 +130,15 @@ namespace MonoDevelop.Projects.Text
}
return null;
}
+
+ public static TextEncoding GetEncoding (int codePage)
+ {
+ foreach (TextEncoding e in SupportedEncodings) {
+ if (e.CodePage == codePage)
+ return e;
+ }
+ return null;
+ }
public static string DefaultEncoding {
get { return "UTF-8"; }
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildEventHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildEventHandler.cs
index ef76135af7..596d7ee072 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildEventHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildEventHandler.cs
@@ -35,10 +35,10 @@ namespace MonoDevelop.Projects
public class BuildEventArgs: EventArgs
{
- IProgressMonitor monitor;
+ ProgressMonitor monitor;
bool success;
- public BuildEventArgs (IProgressMonitor monitor, bool success)
+ public BuildEventArgs (ProgressMonitor monitor, bool success)
{
this.monitor = monitor;
this.success = success;
@@ -48,7 +48,7 @@ namespace MonoDevelop.Projects
this.FailedBuildCount = -1;
}
- public IProgressMonitor ProgressMonitor {
+ public ProgressMonitor ProgressMonitor {
get { return monitor; }
}
@@ -72,7 +72,7 @@ namespace MonoDevelop.Projects
get; set;
}
- public SolutionItem SolutionItem {
+ public SolutionFolderItem SolutionItem {
get; set;
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildResult.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildResult.cs
index 543ec390c1..9bfa798cba 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildResult.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildResult.cs
@@ -43,6 +43,7 @@ namespace MonoDevelop.Projects
string compilerOutput;
List<BuildError> errors = new List<BuildError> ();
IBuildTarget sourceTarget;
+ static BuildResult success = new BuildResult ();
public BuildResult()
{
@@ -65,6 +66,18 @@ namespace MonoDevelop.Projects
}
}
}
+
+ public bool HasErrors {
+ get { return ErrorCount > 0; }
+ }
+
+ public bool HasWarnings {
+ get { return WarningCount > 0; }
+ }
+
+ public static BuildResult Success {
+ get { return success; }
+ }
public ReadOnlyCollection<BuildError> Errors {
get { return errors.AsReadOnly (); }
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildTool.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildTool.cs
index 43b3b5cfd6..46479efbc9 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildTool.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/BuildTool.cs
@@ -34,6 +34,7 @@ using Mono.Addins;
using MonoDevelop.Core.ProgressMonitoring;
using MonoDevelop.Core;
using MonoDevelop.Core.Assemblies;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
@@ -48,6 +49,13 @@ namespace MonoDevelop.Projects
public int Run (string[] arguments)
{
+ var t = RunAsync (arguments);
+ t.Wait ();
+ return t.Result;
+ }
+
+ public async Task<int> RunAsync (string[] arguments)
+ {
Console.WriteLine (BrandingService.BrandApplicationName ("MonoDevelop Build Tool"));
foreach (string s in arguments)
ReadArgument (s);
@@ -93,7 +101,7 @@ namespace MonoDevelop.Projects
}
}
- IProgressMonitor monitor = new ConsoleProjectLoadProgressMonitor (new ConsoleProgressMonitor ());
+ ProgressMonitor monitor = new ConsoleProjectLoadProgressMonitor (new ConsoleProgressMonitor ());
TargetRuntime targetRuntime = null;
TargetRuntime defaultRuntime = Runtime.SystemAssemblyService.DefaultRuntime;
@@ -106,11 +114,16 @@ namespace MonoDevelop.Projects
IBuildTarget item;
if (solFile != null)
- item = Services.ProjectService.ReadWorkspaceItem (monitor, solFile);
+ item = await Services.ProjectService.ReadWorkspaceItem (monitor, solFile) as IBuildTarget;
else
- item = Services.ProjectService.ReadSolutionItem (monitor, itemFile);
+ item = await Services.ProjectService.ReadSolutionItem (monitor, itemFile);
- using (var readItem = item) {
+ if (item == null) {
+ Console.WriteLine ("The file '" + file + "' can't be built");
+ return 1;
+ }
+
+ using (var readItem = (WorkspaceObject)item) {
if (project != null) {
Solution solution = item as Solution;
item = null;
@@ -130,21 +143,25 @@ namespace MonoDevelop.Projects
monitor = new ConsoleProgressMonitor ();
BuildResult res = null;
- if (item is SolutionEntityItem && ((SolutionEntityItem)item).ParentSolution == null) {
+ if (item is SolutionItem && ((SolutionItem)item).ParentSolution == null) {
ConfigurationSelector configuration = new ItemConfigurationSelector (config);
- res = item.RunTarget (monitor, command, configuration);
+ if (command == ProjectService.BuildTarget)
+ res = await item.Build (monitor, configuration);
+ else if (command == ProjectService.CleanTarget)
+ res = await item.Clean (monitor, configuration);
} else {
ConfigurationSelector configuration = new SolutionConfigurationSelector (config);
- SolutionEntityItem solutionEntityItem = item as SolutionEntityItem;
+ SolutionItem solutionEntityItem = item as SolutionItem;
if (solutionEntityItem != null) {
if (command == ProjectService.BuildTarget)
- res = solutionEntityItem.Build (monitor, configuration, true);
+ res = await solutionEntityItem.Build (monitor, configuration, true);
else if (command == ProjectService.CleanTarget)
- solutionEntityItem.Clean (monitor, configuration);
- else
- res = item.RunTarget (monitor, command, configuration);
+ await solutionEntityItem.Clean (monitor, configuration);
+ else if (solutionEntityItem is Project)
+ res = await ((Project)item).RunTarget (monitor, command, configuration);
} else {
- res = item.RunTarget (monitor, command, configuration);
+ Console.WriteLine ("The project '" + project + "' can't be built");
+ return 1;
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ChainedExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ChainedExtension.cs
new file mode 100644
index 0000000000..48af259aba
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ChainedExtension.cs
@@ -0,0 +1,94 @@
+//
+// ChainedExtension.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Reflection;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Projects
+{
+ public class ChainedExtension: IDisposable
+ {
+ ChainedExtension nextInChain;
+
+ internal protected static T FindNextImplementation<T> (ChainedExtension next) where T:class
+ {
+ if (next == null)
+ return null;
+
+ var nextT = next as T;
+ if (nextT == null)
+ return FindNextImplementation<T> (next.nextInChain);
+
+ foreach (var m in typeof(T).GetMembers (BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
+ MethodInfo method = m as MethodInfo;
+ if (method == null) {
+ var prop = m as PropertyInfo;
+ if (prop != null) {
+ method = prop.GetGetMethod ();
+ if (method == null)
+ method = prop.GetSetMethod ();
+ }
+ }
+ if (method != null && method.IsVirtual && method.Name != "InitializeChain") {
+ var tm = next.GetType ().GetMethod (method.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, method.GetParameters ().Select (p=>p.ParameterType).ToArray (), null);
+ if (tm == null)
+ continue;
+ if (tm.DeclaringType != typeof(T))
+ return nextT;
+ }
+ }
+
+ return FindNextImplementation<T> (next.nextInChain);
+ }
+
+ internal void Init (ChainedExtension next)
+ {
+ nextInChain = next;
+ InitializeChain (next);
+ }
+
+ internal protected virtual void InitializeChain (ChainedExtension next)
+ {
+ }
+
+ internal ChainedExtension Next {
+ get { return nextInChain; }
+ }
+
+ internal void DisposeChain ()
+ {
+ Dispose ();
+ if (nextInChain != null)
+ nextInChain.DisposeChain ();
+ }
+
+ public virtual void Dispose ()
+ {
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CleanEventHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CleanEventHandler.cs
index 5d0dc54264..430a43b3fe 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CleanEventHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CleanEventHandler.cs
@@ -33,14 +33,14 @@ namespace MonoDevelop.Projects
public class CleanEventArgs : EventArgs
{
- IProgressMonitor monitor;
+ ProgressMonitor monitor;
- public CleanEventArgs (IProgressMonitor monitor)
+ public CleanEventArgs (ProgressMonitor monitor)
{
this.monitor = monitor;
}
- public IProgressMonitor Monitor {
+ public ProgressMonitor Monitor {
get {
return monitor;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CombineEntryRenamedEventArgs.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CombineEntryRenamedEventArgs.cs
index 41f95e07ad..c7efbcef93 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CombineEntryRenamedEventArgs.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CombineEntryRenamedEventArgs.cs
@@ -37,7 +37,7 @@ namespace MonoDevelop.Projects
string oldName;
string newName;
- public SolutionItemRenamedEventArgs (SolutionItem node, string oldName, string newName)
+ public SolutionItemRenamedEventArgs (SolutionFolderItem node, string oldName, string newName)
: base (node)
{
this.oldName = oldName;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs
index 481bcd9ecf..bbaa65182f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs
@@ -34,6 +34,9 @@ using MonoDevelop.Core.ProgressMonitoring;
using System.Collections.Generic;
using Mono.Cecil.Mdb;
using Mono.Cecil.Cil;
+using System.Threading.Tasks;
+using MonoDevelop.Core.Serialization;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
@@ -46,9 +49,9 @@ namespace MonoDevelop.Projects
AddNewConfiguration ("Default");
}
- public override IEnumerable<string> GetProjectTypes ()
+ protected override void OnGetProjectTypes (HashSet<string> types)
{
- yield return "CompiledAssembly";
+ types.Add ("CompiledAssembly");
}
public override IconId StockIcon {
@@ -137,17 +140,12 @@ namespace MonoDevelop.Projects
return string.Join (Path.DirectorySeparatorChar.ToString (), s1, 0, n);
}
- protected override BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected override Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
{
- return new BuildResult ();
+ return Task.FromResult (BuildResult.Success);
}
- internal protected override bool OnGetNeedsBuilding (ConfigurationSelector configuration)
- {
- return false;
- }
-
- internal protected override void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ protected async override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
ProjectConfiguration conf = (ProjectConfiguration) GetConfiguration (configuration);
monitor.Log.WriteLine (GettextCatalog.GetString ("Running {0} ...", FileName));
@@ -156,8 +154,6 @@ namespace MonoDevelop.Projects
? context.ExternalConsoleFactory.CreateConsole (!conf.PauseConsoleOutput)
: context.ConsoleFactory.CreateConsole (!conf.PauseConsoleOutput);
- AggregatedOperationMonitor aggregatedOperationMonitor = new AggregatedOperationMonitor (monitor);
-
try {
try {
ExecutionCommand executionCommand = CreateExecutionCommand (configuration, conf);
@@ -167,14 +163,16 @@ namespace MonoDevelop.Projects
return;
}
- IProcessAsyncOperation asyncOp = context.ExecutionHandler.Execute (executionCommand, console);
- aggregatedOperationMonitor.AddOperation (asyncOp);
- asyncOp.WaitForCompleted ();
+ ProcessAsyncOperation asyncOp = context.ExecutionHandler.Execute (executionCommand, console);
+ var stopper = monitor.CancellationToken.Register (asyncOp.Cancel);
+
+ await asyncOp.Task;
+
+ stopper.Dispose ();
monitor.Log.WriteLine (GettextCatalog.GetString ("The application exited with code: {0}", asyncOp.ExitCode));
} finally {
console.Dispose ();
- aggregatedOperationMonitor.Dispose ();
}
} catch (Exception ex) {
LoggingService.LogError (string.Format ("Cannot execute \"{0}\"", FileName), ex);
@@ -182,7 +180,7 @@ namespace MonoDevelop.Projects
}
}
- internal protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
{
ProjectConfiguration config = (ProjectConfiguration) GetConfiguration (configuration);
if (config == null)
@@ -201,6 +199,32 @@ namespace MonoDevelop.Projects
cmd.EnvironmentVariables = new Dictionary<string, string> (configuration.EnvironmentVariables);
return cmd;
}
+
+ public override bool HasSlnData {
+ get {
+ return true;
+ }
+ }
+
+ public override DataItem WriteSlnData ()
+ {
+ DataSerializer ser = new DataSerializer (MSBuildProjectService.DataContext);
+ ser.SerializationContext.BaseFile = FileName;
+ ser.SerializationContext.DirectorySeparatorChar = '\\';
+ DataItem data = (DataItem) ser.Serialize (this, typeof(CompiledAssemblyProject));
+ return data;
+ }
+
+ public override void ReadSlnData (DataItem item)
+ {
+ // Remove the default configuration, since new ones will be loaded
+ Configurations.Clear ();
+
+ DataSerializer ser = new DataSerializer (MSBuildProjectService.DataContext);
+ ser.SerializationContext.BaseFile = FileName;
+ ser.SerializationContext.DirectorySeparatorChar = '\\';
+ ser.Deserialize (this, item);
+ }
}
public class CompiledAssemblyExtension: ProjectServiceExtension
@@ -212,22 +236,17 @@ namespace MonoDevelop.Projects
return base.IsSolutionItemFile (fileName);
}
- protected override SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName)
+ protected override Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, string fileName)
{
if (fileName.ToLower().EndsWith (".exe") || fileName.ToLower().EndsWith (".dll")) {
- CompiledAssemblyProject p = new CompiledAssemblyProject ();
- p.LoadFrom (fileName);
- return p;
+ return Task<SolutionItem>.Factory.StartNew (delegate {
+ CompiledAssemblyProject p = new CompiledAssemblyProject ();
+ p.LoadFrom (fileName);
+ return p;
+ });
}
return base.LoadSolutionItem (monitor, fileName);
}
-
- public override void Save (IProgressMonitor monitor, SolutionEntityItem item)
- {
-// if (item is CompiledAssemblyProject)
-// return;
- base.Save (monitor, item);
- }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ConfigurationEventHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ConfigurationEventHandler.cs
index fdec84f720..61d537dd5f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ConfigurationEventHandler.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ConfigurationEventHandler.cs
@@ -38,7 +38,7 @@ namespace MonoDevelop.Projects
{
ItemConfiguration configuration;
- public ConfigurationEventArgs (SolutionEntityItem entry, ItemConfiguration configuration): base (entry)
+ public ConfigurationEventArgs (SolutionItem entry, ItemConfiguration configuration): base (entry)
{
this.configuration = configuration;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommand.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommand.cs
index 115edb369f..f74b6f51e8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommand.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommand.cs
@@ -35,6 +35,8 @@ using MonoDevelop.Core.Execution;
using MonoDevelop.Core.StringParsing;
using System.Collections.Generic;
using MonoDevelop.Core.ProgressMonitoring;
+using System.Threading.Tasks;
+using System.Threading;
namespace MonoDevelop.Projects
{
@@ -98,7 +100,7 @@ namespace MonoDevelop.Projects
set { pauseExternalConsole = value; }
}
- public string GetCommandFile (IWorkspaceObject entry, ConfigurationSelector configuration)
+ public string GetCommandFile (WorkspaceObject entry, ConfigurationSelector configuration)
{
string exe, args;
StringTagModel tagSource = GetTagModel (entry, configuration);
@@ -106,7 +108,7 @@ namespace MonoDevelop.Projects
return exe;
}
- public string GetCommandArgs (IWorkspaceObject entry, ConfigurationSelector configuration)
+ public string GetCommandArgs (WorkspaceObject entry, ConfigurationSelector configuration)
{
string exe, args;
StringTagModel tagSource = GetTagModel (entry, configuration);
@@ -114,7 +116,7 @@ namespace MonoDevelop.Projects
return args;
}
- public FilePath GetCommandWorkingDir (IWorkspaceObject entry, ConfigurationSelector configuration)
+ public FilePath GetCommandWorkingDir (WorkspaceObject entry, ConfigurationSelector configuration)
{
StringTagModel tagSource = GetTagModel (entry, configuration);
if (string.IsNullOrEmpty (workingdir))
@@ -135,10 +137,10 @@ namespace MonoDevelop.Projects
return cmd;
}
- StringTagModel GetTagModel (IWorkspaceObject entry, ConfigurationSelector configuration)
+ StringTagModel GetTagModel (WorkspaceObject entry, ConfigurationSelector configuration)
{
- if (entry is SolutionItem)
- return ((SolutionItem)entry).GetStringTagModel (configuration);
+ if (entry is SolutionFolderItem)
+ return ((SolutionFolderItem)entry).GetStringTagModel (configuration);
else if (entry is WorkspaceItem)
return ((WorkspaceItem)entry).GetStringTagModel ();
else
@@ -172,7 +174,7 @@ namespace MonoDevelop.Projects
args = StringParserService.Parse (args, tagSource);
}
- public ProcessExecutionCommand CreateExecutionCommand (IWorkspaceObject entry, ConfigurationSelector configuration)
+ public ProcessExecutionCommand CreateExecutionCommand (WorkspaceObject entry, ConfigurationSelector configuration)
{
string exe, args;
StringTagModel tagSource = GetTagModel (entry, configuration);
@@ -207,12 +209,12 @@ namespace MonoDevelop.Projects
return cmd;
}
- public void Execute (IProgressMonitor monitor, IWorkspaceObject entry, ConfigurationSelector configuration)
+ public Task<bool> Execute (ProgressMonitor monitor, WorkspaceObject entry, ConfigurationSelector configuration)
{
- Execute (monitor, entry, null, configuration);
+ return Execute (monitor, entry, null, configuration);
}
- public bool CanExecute (IWorkspaceObject entry, ExecutionContext context, ConfigurationSelector configuration)
+ public bool CanExecute (WorkspaceObject entry, ExecutionContext context, ConfigurationSelector configuration)
{
if (string.IsNullOrEmpty (command))
return false;
@@ -224,7 +226,7 @@ namespace MonoDevelop.Projects
return context.ExecutionHandler.CanExecute (cmd);
}
- public void Execute (IProgressMonitor monitor, IWorkspaceObject entry, ExecutionContext context,
+ public async Task<bool> Execute (ProgressMonitor monitor, WorkspaceObject entry, ExecutionContext context,
ConfigurationSelector configuration)
{
ProcessExecutionCommand cmd = CreateExecutionCommand (entry, configuration);
@@ -233,12 +235,12 @@ namespace MonoDevelop.Projects
if (!Directory.Exists (cmd.WorkingDirectory)) {
monitor.ReportError (GettextCatalog.GetString ("Custom command working directory does not exist"), null);
- return;
+ return false;
}
- AggregatedOperationMonitor aggMon = null;
- IProcessAsyncOperation oper = null;
+ ProcessAsyncOperation oper = null;
IConsole console = null;
+ var result = true;
try {
if (context != null) {
@@ -254,35 +256,33 @@ namespace MonoDevelop.Projects
cmd.WorkingDirectory, console, null);
} else {
oper = Runtime.ProcessService.StartProcess (cmd.Command, cmd.Arguments,
- cmd.WorkingDirectory, monitor.Log, monitor.Log, null, false);
+ cmd.WorkingDirectory, monitor.Log, monitor.Log, null, false).ProcessAsyncOperation;
}
}
- aggMon = new AggregatedOperationMonitor (monitor, oper);
- oper.WaitForCompleted ();
- if (!oper.Success) {
+
+ var stopper = monitor.CancellationToken.Register (oper.Cancel);
+
+ await oper.Task;
+
+ stopper.Dispose ();
+
+ if (oper.ExitCode != 0) {
monitor.ReportError ("Custom command failed (exit code: " + oper.ExitCode + ")", null);
}
} catch (Win32Exception w32ex) {
monitor.ReportError (GettextCatalog.GetString ("Failed to execute custom command '{0}': {1}",
cmd.Command, w32ex.Message), null);
- return;
+ return false;
} catch (Exception ex) {
LoggingService.LogError ("Command execution failed", ex);
throw new UserException (GettextCatalog.GetString ("Command execution failed: {0}", ex.Message));
} finally {
- if (oper == null || !oper.Success) {
- monitor.AsyncOperation.Cancel ();
- }
- if (oper != null) {
- oper.Dispose ();
- }
+ result = oper != null && oper.ExitCode == 0;
if (console != null) {
console.Dispose ();
}
- if (aggMon != null) {
- aggMon.Dispose ();
- }
}
+ return result;
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandCollection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandCollection.cs
index 797ee6da64..ee37994054 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandCollection.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandCollection.cs
@@ -29,6 +29,7 @@
using System;
using System.Collections.Generic;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
@@ -48,19 +49,20 @@ namespace MonoDevelop.Projects
Add (cmd.Clone ());
}
- public void ExecuteCommand (IProgressMonitor monitor, IWorkspaceObject entry, CustomCommandType type, ConfigurationSelector configuration)
+ public Task<bool> ExecuteCommand (ProgressMonitor monitor, WorkspaceObject entry, CustomCommandType type, ConfigurationSelector configuration)
{
- ExecuteCommand (monitor, entry, type, null, configuration);
+ return ExecuteCommand (monitor, entry, type, null, configuration);
}
- public void ExecuteCommand (IProgressMonitor monitor, IWorkspaceObject entry, CustomCommandType type, ExecutionContext context, ConfigurationSelector configuration)
+ public async Task<bool> ExecuteCommand (ProgressMonitor monitor, WorkspaceObject entry, CustomCommandType type, ExecutionContext context, ConfigurationSelector configuration)
{
foreach (CustomCommand cmd in this) {
- if (cmd.Type == type)
- cmd.Execute (monitor, entry, context, configuration);
- if (monitor.IsCancelRequested)
- break;
+ if (cmd.Type == type) {
+ if (!await cmd.Execute (monitor, entry, context, configuration))
+ return false;
+ }
}
+ return true;
}
public bool HasCommands (CustomCommandType type)
@@ -71,7 +73,7 @@ namespace MonoDevelop.Projects
return false;
}
- public bool CanExecute (IWorkspaceObject entry, CustomCommandType type, ExecutionContext context, ConfigurationSelector configuration)
+ public bool CanExecute (WorkspaceObject entry, CustomCommandType type, ExecutionContext context, ConfigurationSelector configuration)
{
// Note: if this gets changed to return true if *any* of the commands can execute, then
// ExecuteCommand() needs to be fixed to only execute commands that can be executed.
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandExtension.cs
deleted file mode 100644
index fc0a9bf77b..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CustomCommandExtension.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-// CustomCommandExtension.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2007 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-//
-
-
-using System;
-using MonoDevelop.Core;
-using System.CodeDom.Compiler;
-using MonoDevelop.Core.Execution;
-
-namespace MonoDevelop.Projects
-{
- internal class CustomCommandExtension: ProjectServiceExtension
- {
- protected override BuildResult Build (IProgressMonitor monitor, SolutionEntityItem entry, ConfigurationSelector configuration)
- {
- SolutionItemConfiguration conf = entry.GetConfiguration (configuration) as SolutionItemConfiguration;
- if (conf != null) {
- if (conf.CustomCommands.CanExecute (entry, CustomCommandType.BeforeBuild, null, configuration))
- conf.CustomCommands.ExecuteCommand (monitor, entry, CustomCommandType.BeforeBuild, configuration);
-
- if (monitor.IsCancelRequested)
- return new BuildResult (new CompilerResults (null), "");
- }
-
- BuildResult res = base.Build (monitor, entry, configuration);
-
- if (conf != null && !monitor.IsCancelRequested && !res.Failed) {
- if (conf.CustomCommands.CanExecute (entry, CustomCommandType.AfterBuild, null, configuration))
- conf.CustomCommands.ExecuteCommand (monitor, entry, CustomCommandType.AfterBuild, configuration);
- }
-
- return res;
- }
-
- protected override void Clean (IProgressMonitor monitor, SolutionEntityItem entry, ConfigurationSelector configuration)
- {
- SolutionItemConfiguration conf = entry.GetConfiguration (configuration) as SolutionItemConfiguration;
- if (conf != null) {
- if (conf.CustomCommands.CanExecute (entry, CustomCommandType.BeforeClean, null, configuration))
- conf.CustomCommands.ExecuteCommand (monitor, entry, CustomCommandType.BeforeClean, configuration);
-
- if (monitor.IsCancelRequested)
- return;
- }
-
- base.Clean (monitor, entry, configuration);
-
- if (conf != null && !monitor.IsCancelRequested) {
- if (conf.CustomCommands.CanExecute (entry, CustomCommandType.AfterClean, null, configuration))
- conf.CustomCommands.ExecuteCommand (monitor, entry, CustomCommandType.AfterClean, configuration);
- }
- }
-
- protected override void Execute (IProgressMonitor monitor, SolutionEntityItem entry, ExecutionContext context, ConfigurationSelector configuration)
- {
- SolutionItemConfiguration conf = entry.GetConfiguration (configuration) as SolutionItemConfiguration;
- if (conf != null) {
- ExecutionContext localContext = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, context.ConsoleFactory, context.ExecutionTarget);
-
- if (conf.CustomCommands.CanExecute (entry, CustomCommandType.BeforeExecute, localContext, configuration))
- conf.CustomCommands.ExecuteCommand (monitor, entry, CustomCommandType.BeforeExecute, localContext, configuration);
-
- if (monitor.IsCancelRequested)
- return;
- }
-
- base.Execute (monitor, entry, context, configuration);
-
- if (conf != null && !monitor.IsCancelRequested) {
- ExecutionContext localContext = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, context.ConsoleFactory, context.ExecutionTarget);
-
- if (conf.CustomCommands.CanExecute (entry, CustomCommandType.AfterExecute, localContext, configuration))
- conf.CustomCommands.ExecuteCommand (monitor, entry, CustomCommandType.AfterExecute, localContext, configuration);
- }
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetAssemblyProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetAssemblyProject.cs
deleted file mode 100644
index cba01e80c1..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetAssemblyProject.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// DotNetAssemblyProject.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Xml;
-using MonoDevelop.Core;
-using MonoDevelop.Core.Assemblies;
-
-namespace MonoDevelop.Projects
-{
- [ProjectModelDataItem ("DotNetProject")]
- public class DotNetAssemblyProject: DotNetProject
- {
- public DotNetAssemblyProject ()
- {
- }
-
- public DotNetAssemblyProject (string languageName) : base (languageName)
- {
- }
-
- public DotNetAssemblyProject (string languageName, ProjectCreateInformation projectCreateInfo, XmlElement projectOptions):
- base (languageName, projectCreateInfo, projectOptions)
- {
- }
-
- public override System.Collections.Generic.IEnumerable<string> GetProjectTypes ()
- {
- yield return "DotNetAssembly";
- foreach (var pt in base.GetProjectTypes ())
- yield return pt;
- }
-
- public override bool SupportsFramework (TargetFramework framework)
- {
- // DotNetAssemblyProject can only generate assemblies for the regular framework.
- // Special frameworks such as Moonlight or MonoTouch must subclass DotNetProject directly.
- if (!framework.CanReferenceAssembliesTargetingFramework (TargetFrameworkMoniker.NET_1_1))
- return false;
-
- return base.SupportsFramework (framework);
- }
-
- public override TargetFrameworkMoniker GetDefaultTargetFrameworkForFormat (FileFormat format)
- {
- switch (format.Id) {
- case "MSBuild05":
- return TargetFrameworkMoniker.NET_2_0;
- case "MSBuild08":
- return TargetFrameworkMoniker.NET_2_0;
- case "MSBuild10":
- case "MSBuild12":
- return TargetFrameworkMoniker.NET_4_0;
- }
- return Services.ProjectService.DefaultTargetFramework.Id;
- }
-
- protected override string GetDefaultTargetPlatform (ProjectCreateInformation projectCreateInfo)
- {
- if (CompileTarget == CompileTarget.Library)
- return string.Empty;
-
- // Guess a good default platform for the project
- if (projectCreateInfo.ParentFolder != null && projectCreateInfo.ParentFolder.ParentSolution != null) {
- ItemConfiguration conf = projectCreateInfo.ParentFolder.ParentSolution.GetConfiguration (projectCreateInfo.ActiveConfiguration);
- if (conf != null)
- return conf.Platform;
- else {
- string curName, curPlatform, bestPlatform = null;
- string sconf = projectCreateInfo.ActiveConfiguration.ToString ();
- ItemConfiguration.ParseConfigurationId (sconf, out curName, out curPlatform);
- foreach (ItemConfiguration ic in projectCreateInfo.ParentFolder.ParentSolution.Configurations) {
- if (ic.Platform == curPlatform)
- return curPlatform;
- if (ic.Name == curName)
- bestPlatform = ic.Platform;
- }
- if (bestPlatform != null)
- return bestPlatform;
- }
- }
- return Services.ProjectService.DefaultPlatformTarget;
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ConfigurationParameters.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetCompilerParameters.cs
index 9ff5f46356..c45f57b51c 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ConfigurationParameters.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetCompilerParameters.cs
@@ -31,9 +31,7 @@ using System.Linq;
namespace MonoDevelop.Projects
{
- ///<summary>This should really be called DotNetCompilerParameters</summary>
- [DataItem (FallbackType=typeof(UnknownCompilationParameters))]
- public abstract class ConfigurationParameters: ProjectParameters
+ public abstract class DotNetCompilerParameters: ProjectParameters
{
DotNetProjectConfiguration configuration;
@@ -58,9 +56,9 @@ namespace MonoDevelop.Projects
return GetDefineSymbols ().Any (s => s == symbol);
}
- public new ConfigurationParameters Clone ()
+ public new DotNetCompilerParameters Clone ()
{
- return (ConfigurationParameters) base.Clone ();
+ return (DotNetCompilerParameters) base.Clone ();
}
public DotNetProjectConfiguration ParentConfiguration {
@@ -71,11 +69,7 @@ namespace MonoDevelop.Projects
ParentProject = configuration.ParentItem;
}
}
- }
- public abstract class DotNetConfigurationParameters : ConfigurationParameters
- {
- public abstract bool NoStdLib { get; set; }
+ public virtual bool NoStdLib { get; set; }
}
-
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
index d6a7a8c7f0..e2148a39ac 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
@@ -2,7 +2,7 @@
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
-//
+//
// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -44,53 +44,67 @@ using MonoDevelop.Projects.Extensions;
using MonoDevelop.Projects.Formats.MSBuild;
using MonoDevelop.Core.Assemblies;
using System.Globalization;
+using System.Threading.Tasks;
+using Mono.Addins;
namespace MonoDevelop.Projects
{
- [DataInclude(typeof(DotNetProjectConfiguration))]
- [ProjectModelDataItem ("AbstractDotNetProject")]
- public abstract class DotNetProject : Project, IAssemblyProject, IDotNetFileContainer
+ public class DotNetProject : Project, IAssemblyProject, IDotNetFileContainer
{
bool usePartialTypes = true;
- ProjectParameters languageParameters;
DirectoryAssemblyContext privateAssemblyContext;
ComposedAssemblyContext composedAssemblyContext;
IAssemblyContext currentRuntimeContext;
- [ItemProperty("OutputType")]
CompileTarget compileTarget;
IDotNetLanguageBinding languageBinding;
protected ProjectReferenceCollection projectReferences;
- [ItemProperty("RootNamespace", DefaultValue = "")]
protected string defaultNamespace = String.Empty;
-
- public DotNetProject ()
+
+ protected DotNetProject ()
{
- Runtime.SystemAssemblyService.DefaultRuntimeChanged += RuntimeSystemAssemblyServiceDefaultRuntimeChanged;
+ Initialize (this);
+ }
+
+ protected DotNetProject (string languageName, params string[] flavorIds): base (flavorIds)
+ {
+ this.languageName = languageName;
+ Initialize (this);
+ }
+
+ protected override void OnInitialize ()
+ {
+ UseMSBuildEngineByDefault = true;
+ RequireMSBuildEngine = false;
projectReferences = new ProjectReferenceCollection ();
Items.Bind (projectReferences);
- if (IsLibraryBasedProjectType)
- CompileTarget = CompileTarget.Library;
FileService.FileRemoved += OnFileRemoved;
+ Runtime.SystemAssemblyService.DefaultRuntimeChanged += RuntimeSystemAssemblyServiceDefaultRuntimeChanged;
+
+ base.OnInitialize ();
+
+ if (languageName == null)
+ languageName = MSBuildProjectService.GetLanguageFromGuid (TypeGuid);
}
- public DotNetProject (string languageName) : this()
+ protected override void OnExtensionChainInitialized ()
{
- // Language name must be set before the item handler is assigned
- this.languageName = languageName;
- this.languageBinding = FindLanguage (languageName);
-
- if (this.languageBinding != null)
- this.StockIcon = this.languageBinding.ProjectStockIcon;
+ base.OnExtensionChainInitialized ();
this.usePartialTypes = SupportsPartialTypes;
+
+ if (LanguageBinding != null)
+ this.StockIcon = LanguageBinding.ProjectStockIcon;
+
+ if (IsLibraryBasedProjectType)
+ CompileTarget = CompileTarget.Library;
}
- public DotNetProject (string languageName, ProjectCreateInformation projectCreateInfo, XmlElement projectOptions) : this(languageName)
+ public override void InitializeNew (ProjectCreateInformation projectCreateInfo, XmlElement projectOptions)
{
if ((projectOptions != null) && (projectOptions.Attributes ["Target"] != null))
CompileTarget = (CompileTarget)Enum.Parse (typeof(CompileTarget), projectOptions.Attributes ["Target"].Value);
@@ -98,8 +112,7 @@ namespace MonoDevelop.Projects
CompileTarget = CompileTarget.Library;
if (this.LanguageBinding != null) {
- LanguageParameters = languageBinding.CreateProjectParameters (projectOptions);
-
+
bool externalConsole = false;
string platform = null;
@@ -117,22 +130,22 @@ namespace MonoDevelop.Projects
}
string platformSuffix = string.IsNullOrEmpty (platform) ? string.Empty : "|" + platform;
DotNetProjectConfiguration configDebug = CreateConfiguration ("Debug" + platformSuffix) as DotNetProjectConfiguration;
- configDebug.CompilationParameters = languageBinding.CreateCompilationParameters (projectOptions);
+ configDebug.CompilationParameters = LanguageBinding.CreateCompilationParameters (projectOptions);
configDebug.DebugMode = true;
configDebug.ExternalConsole = externalConsole;
configDebug.PauseConsoleOutput = externalConsole;
Configurations.Add (configDebug);
DotNetProjectConfiguration configRelease = CreateConfiguration ("Release" + platformSuffix) as DotNetProjectConfiguration;
-
+
if (projectOptions != null) {
XmlElement releaseProjectOptions = (XmlElement)projectOptions.CloneNode (true);
releaseProjectOptions.SetAttribute ("Release", "True");
- configRelease.CompilationParameters = languageBinding.CreateCompilationParameters (releaseProjectOptions);
+ configRelease.CompilationParameters = LanguageBinding.CreateCompilationParameters (releaseProjectOptions);
} else {
- configRelease.CompilationParameters = languageBinding.CreateCompilationParameters (null);
+ configRelease.CompilationParameters = LanguageBinding.CreateCompilationParameters (null);
}
-
+
configRelease.CompilationParameters.RemoveDefineSymbol ("DEBUG");
configRelease.DebugMode = false;
configRelease.ExternalConsole = externalConsole;
@@ -184,9 +197,32 @@ namespace MonoDevelop.Projects
return Runtime.SystemAssemblyService.GetTargetFramework (moniker);
}
- public override IEnumerable<string> GetProjectTypes ()
+ protected override void OnGetProjectTypes (HashSet<string> types)
+ {
+ types.Add ("DotNet");
+ types.Add ("DotNetAssembly");
+ }
+
+ DotNetProjectExtension projectExtension;
+ DotNetProjectExtension ProjectExtension {
+ get {
+ if (projectExtension == null)
+ projectExtension = ExtensionChain.GetExtension<DotNetProjectExtension> ();
+ return projectExtension;
+ }
+ }
+
+ protected override IEnumerable<WorkspaceObjectExtension> CreateDefaultExtensions ()
+ {
+ return base.CreateDefaultExtensions ().Concat (Enumerable.Repeat (new DefaultDotNetProjectExtension (), 1));
+ }
+
+ protected override ProjectItem OnCreateProjectItem (IMSBuildItemEvaluated item)
{
- yield return "DotNet";
+ if (item.Name == "Reference" || item.Name == "ProjectReference")
+ return new ProjectReference ();
+
+ return base.OnCreateProjectItem (item);
}
private string languageName;
@@ -195,22 +231,53 @@ namespace MonoDevelop.Projects
}
public override string[] SupportedLanguages {
- get { return new string[] {"",languageName}; }
+ get { return ProjectExtension.SupportedLanguages; }
}
public virtual bool IsLibraryBasedProjectType {
- get { return false; }
+ get { return ProjectExtension.IsLibraryBasedProjectType; }
+ }
+
+ public bool IsPortableLibrary {
+ get { return GetService<PortableDotNetProjectFlavor> () != null; }
}
public virtual bool GeneratesDebugInfoFile {
- get { return true; }
+ get { return ProjectExtension.GeneratesDebugInfoFile; }
}
-
- protected virtual string GetDefaultTargetPlatform (ProjectCreateInformation projectCreateInfo)
+
+ protected string GetDefaultTargetPlatform (ProjectCreateInformation projectCreateInfo)
{
- return string.Empty;
+ return ProjectExtension.OnGetDefaultTargetPlatform (projectCreateInfo);
}
-
+
+ protected virtual string OnGetDefaultTargetPlatform (ProjectCreateInformation projectCreateInfo)
+ {
+ if (CompileTarget == CompileTarget.Library)
+ return string.Empty;
+
+ // Guess a good default platform for the project
+ if (projectCreateInfo.ParentFolder != null && projectCreateInfo.ParentFolder.ParentSolution != null) {
+ ItemConfiguration conf = projectCreateInfo.ParentFolder.ParentSolution.GetConfiguration (projectCreateInfo.ActiveConfiguration);
+ if (conf != null)
+ return conf.Platform;
+ else {
+ string curName, curPlatform, bestPlatform = null;
+ string sconf = projectCreateInfo.ActiveConfiguration.ToString ();
+ ItemConfiguration.ParseConfigurationId (sconf, out curName, out curPlatform);
+ foreach (ItemConfiguration ic in projectCreateInfo.ParentFolder.ParentSolution.Configurations) {
+ if (ic.Platform == curPlatform)
+ return curPlatform;
+ if (ic.Name == curName)
+ bestPlatform = ic.Platform;
+ }
+ if (bestPlatform != null)
+ return bestPlatform;
+ }
+ }
+ return Services.ProjectService.DefaultPlatformTarget;
+ }
+
public ProjectReferenceCollection References {
get { return projectReferences; }
}
@@ -229,6 +296,10 @@ namespace MonoDevelop.Projects
public virtual bool CanReferenceProject (DotNetProject targetProject, out string reason)
{
+ return ProjectExtension.OnGetCanReferenceProject (targetProject, out reason);
+ }
+ bool CheckCanReferenceProject (DotNetProject targetProject, out string reason)
+ {
if (!TargetFramework.CanReferenceAssembliesTargetingFramework (targetProject.TargetFramework)) {
reason = GettextCatalog.GetString ("Incompatible target framework: {0}", targetProject.TargetFramework.Id);
return false;
@@ -264,20 +335,6 @@ namespace MonoDevelop.Projects
}
}
- [ItemProperty("LanguageParameters")]
- public ProjectParameters LanguageParameters {
- get {
- if (languageParameters == null && LanguageBinding != null)
- LanguageParameters = LanguageBinding.CreateProjectParameters (null);
- return languageParameters;
- }
- internal set {
- languageParameters = value;
- if (languageParameters != null)
- languageParameters.ParentProject = this;
- }
- }
-
/// <summary>
/// Default namespace setting. May be empty, use GetDefaultNamespace to get a usable value.
/// </summary>
@@ -288,7 +345,7 @@ namespace MonoDevelop.Projects
NotifyModified ("DefaultNamespace");
}
}
-
+
/// <summary>
/// Given a namespace, removes from it the implicit namespace of the project,
/// if there is one. This depends on the target language. For example, in VB.NET
@@ -296,7 +353,7 @@ namespace MonoDevelop.Projects
/// </summary>
public string StripImplicitNamespace (string ns)
{
- if ((LanguageParameters is DotNetProjectParameters) && ((DotNetProjectParameters)LanguageParameters).DefaultNamespaceIsImplicit) {
+ if (DefaultNamespaceIsImplicit) {
if (DefaultNamespace.Length > 0 && ns.StartsWith (DefaultNamespace + "."))
return ns.Substring (DefaultNamespace.Length + 1);
else if (DefaultNamespace == ns)
@@ -305,23 +362,26 @@ namespace MonoDevelop.Projects
return ns;
}
+ public bool DefaultNamespaceIsImplicit { get; set; }
+
IResourceHandler resourceHandler;
public IResourceHandler ResourceHandler {
get {
if (resourceHandler == null) {
DotNetNamingPolicy pol = Policies.Get<DotNetNamingPolicy> ();
- if (pol.ResourceNamePolicy == ResourceNamePolicy.FileFormatDefault)
- resourceHandler = ItemHandler as IResourceHandler;
- else if (pol.ResourceNamePolicy == ResourceNamePolicy.MSBuild)
- resourceHandler = MSBuildProjectService.GetResourceHandlerForItem (this);
- if (resourceHandler == null)
+ if (pol.ResourceNamePolicy == ResourceNamePolicy.FileFormatDefault || pol.ResourceNamePolicy == ResourceNamePolicy.MSBuild) {
+ resourceHandler = GetService<IResourceHandler> ();
+ if (resourceHandler == null)
+ resourceHandler = MSBuildResourceHandler.Instance;
+ }
+ else
resourceHandler = DefaultResourceHandler.Instance;
}
return resourceHandler;
}
}
-
+
TargetFramework targetFramework;
public TargetFramework TargetFramework {
@@ -350,18 +410,23 @@ namespace MonoDevelop.Projects
public TargetRuntime TargetRuntime {
get { return Runtime.SystemAssemblyService.DefaultRuntime; }
}
-
+
/// <summary>
/// Gets the target framework for new projects
/// </summary>
/// <returns>
/// The default target framework identifier.
/// </returns>
- public virtual TargetFrameworkMoniker GetDefaultTargetFrameworkId ()
+ public TargetFrameworkMoniker GetDefaultTargetFrameworkId ()
+ {
+ return ProjectExtension.OnGetDefaultTargetFrameworkId ();
+ }
+
+ protected virtual TargetFrameworkMoniker OnGetDefaultTargetFrameworkId ()
{
return Services.ProjectService.DefaultTargetFramework.Id;
}
-
+
/// <summary>
/// Returns the default framework for a given format
/// </summary>
@@ -375,11 +440,25 @@ namespace MonoDevelop.Projects
/// This method is used to determine what's the correct target framework for a project
/// deserialized using a specific format.
/// </remarks>
- public virtual TargetFrameworkMoniker GetDefaultTargetFrameworkForFormat (FileFormat format)
+ public TargetFrameworkMoniker GetDefaultTargetFrameworkForFormat (FileFormat format)
+ {
+ return ProjectExtension.OnGetDefaultTargetFrameworkForFormat (format);
+ }
+
+ protected virtual TargetFrameworkMoniker OnGetDefaultTargetFrameworkForFormat (FileFormat format)
{
+ switch (format.Id) {
+ case "MSBuild05":
+ return TargetFrameworkMoniker.NET_2_0;
+ case "MSBuild08":
+ return TargetFrameworkMoniker.NET_2_0;
+ case "MSBuild10":
+ case "MSBuild12":
+ return TargetFrameworkMoniker.NET_4_0;
+ }
return GetDefaultTargetFrameworkId ();
}
-
+
public IAssemblyContext AssemblyContext {
get {
if (composedAssemblyContext == null) {
@@ -400,8 +479,17 @@ namespace MonoDevelop.Projects
}
}
- public virtual bool SupportsFramework (TargetFramework framework)
+ public bool SupportsFramework (TargetFramework framework)
+ {
+ return ProjectExtension.OnGetSupportsFramework (framework);
+ }
+
+ protected virtual bool OnSupportsFramework (TargetFramework framework)
{
+ // DotNetAssemblyProject can only generate assemblies for the regular framework.
+ // Special frameworks such as Moonlight or MonoTouch must override SupportsFramework.
+ if (!framework.CanReferenceAssembliesTargetingFramework (TargetFrameworkMoniker.NET_1_1))
+ return false;
if (LanguageBinding == null)
return false;
ClrVersion[] versions = LanguageBinding.GetSupportedClrVersions ();
@@ -414,7 +502,6 @@ namespace MonoDevelop.Projects
return false;
}
- [ItemProperty(DefaultValue = true)]
public bool UsePartialTypes {
get { return usePartialTypes; }
set { usePartialTypes = value; }
@@ -426,16 +513,16 @@ namespace MonoDevelop.Projects
composedAssemblyContext.Dispose ();
// composedAssemblyContext = null;
}
-
+
// languageParameters = null;
// privateAssemblyContext = null;
// currentRuntimeContext = null;
// languageBinding = null;
// projectReferences = null;
-
+
Runtime.SystemAssemblyService.DefaultRuntimeChanged -= RuntimeSystemAssemblyServiceDefaultRuntimeChanged;
FileService.FileRemoved -= OnFileRemoved;
-
+
base.Dispose ();
}
@@ -477,7 +564,7 @@ namespace MonoDevelop.Projects
// cached and won't take into account unsubscriptions until the next dispatch
if (Disposed)
return;
-
+
base.OnFileChanged (source, e);
foreach (FileEventInfo ei in e)
CheckReferenceChange (ei.FileName);
@@ -501,24 +588,24 @@ namespace MonoDevelop.Projects
this.References.Add (prNew);
}
}
-
+
internal protected override void PopulateOutputFileList (List<FilePath> list, ConfigurationSelector configuration)
{
base.PopulateOutputFileList (list, configuration);
DotNetProjectConfiguration conf = GetConfiguration (configuration) as DotNetProjectConfiguration;
-
+
// Debug info file
-
+
if (conf.DebugMode) {
string mdbFile = TargetRuntime.GetAssemblyDebugInfoFile (conf.CompiledOutputName);
list.Add (mdbFile);
}
-
+
// Generated satellite resource files
-
+
FilePath outputDir = conf.OutputDirectory;
string satelliteAsmName = Path.GetFileNameWithoutExtension (conf.CompiledOutputName) + ".resources.dll";
-
+
HashSet<string> cultures = new HashSet<string> ();
foreach (ProjectFile finfo in Files) {
if (finfo.Subtype == Subtype.Directory || finfo.BuildAction != BuildAction.EmbeddedResource)
@@ -532,7 +619,7 @@ namespace MonoDevelop.Projects
}
}
}
-
+
[ThreadStatic]
static int supportReferDistance;
[ThreadStatic]
@@ -561,13 +648,13 @@ namespace MonoDevelop.Projects
//rename the app.config file
list.Remove ("app.config");
list.Remove ("App.config");
-
+
ProjectFile appConfig = Files.FirstOrDefault (f => f.FilePath.FileName.Equals ("app.config", StringComparison.CurrentCultureIgnoreCase));
if (appConfig != null) {
string output = GetOutputFileName (configuration).FileName;
list.Add (appConfig.FilePath, true, output + ".config");
}
-
+
//collect all the "local copy" references and their attendant files
foreach (ProjectReference projectReference in References) {
if (!projectReference.LocalCopy || !projectReference.CanSetLocalCopy)
@@ -614,7 +701,7 @@ namespace MonoDevelop.Projects
}
}
}
-
+
//Given a filename like foo.it.resx, get 'it', if its
//a valid culture
//Note: hand-written as this can get called lotsa times
@@ -664,14 +751,14 @@ namespace MonoDevelop.Projects
return cultureNamesTable;
}
}
-
+
IEnumerable<string> GetAssemblyRefsRec (string fileName, HashSet<string> visited)
{
// Recursivelly finds assemblies referenced by the given assembly
-
+
if (!visited.Add (fileName))
yield break;
-
+
if (!File.Exists (fileName)) {
string ext = Path.GetExtension (fileName).ToLower ();
if (ext == ".dll" || ext == ".exe")
@@ -683,7 +770,7 @@ namespace MonoDevelop.Projects
else
yield break;
}
-
+
yield return fileName;
foreach (var reference in SystemAssemblyService.GetAssemblyReferences (fileName)) {
@@ -705,9 +792,9 @@ namespace MonoDevelop.Projects
return newReferenceInformation;
}
- public override IEnumerable<SolutionItem> GetReferencedItems (ConfigurationSelector configuration)
+ protected override IEnumerable<SolutionItem> OnGetReferencedItems (ConfigurationSelector configuration)
{
- List<SolutionItem> items = new List<SolutionItem> (base.GetReferencedItems (configuration));
+ var items = new List<SolutionItem> (base.OnGetReferencedItems (configuration));
if (ParentSolution == null)
return items;
@@ -745,23 +832,24 @@ namespace MonoDevelop.Projects
/// </param>
public IEnumerable<string> GetReferencedAssemblies (ConfigurationSelector configuration, bool includeProjectReferences)
{
- return Services.ProjectService.GetExtensionChain (this).GetReferencedAssemblies (this, configuration, includeProjectReferences);
+ return ProjectExtension.OnGetReferencedAssemblies (configuration, includeProjectReferences);
}
internal protected virtual IEnumerable<string> OnGetReferencedAssemblies (ConfigurationSelector configuration, bool includeProjectReferences)
{
- IAssemblyReferenceHandler handler = this.ItemHandler as IAssemblyReferenceHandler;
- if (handler != null) {
+ if (CheckUseMSBuildEngine (configuration)) {
if (includeProjectReferences) {
foreach (ProjectReference pref in References.Where (pr => pr.ReferenceType == ReferenceType.Project)) {
foreach (string asm in pref.GetReferencedFileNames (configuration))
yield return asm;
}
}
- foreach (string file in handler.GetAssemblyReferences (configuration))
- yield return file;
- }
- else {
+ // Get the references list from the msbuild project
+ RemoteProjectBuilder builder = GetProjectBuilder ();
+ var configs = GetConfigurations (configuration);
+ foreach (var r in builder.ResolveAssemblyReferences (configs))
+ yield return r;
+ } else {
foreach (ProjectReference pref in References) {
if (includeProjectReferences || pref.ReferenceType != ReferenceType.Project) {
foreach (string asm in pref.GetReferencedFileNames (configuration))
@@ -772,12 +860,8 @@ namespace MonoDevelop.Projects
var config = (DotNetProjectConfiguration)GetConfiguration (configuration);
bool noStdLib = false;
- if (config != null) {
- var parameters = config.CompilationParameters as DotNetConfigurationParameters;
- if (parameters != null) {
- noStdLib = parameters.NoStdLib;
- }
- }
+ if (config != null)
+ noStdLib = config.CompilationParameters.NoStdLib;
// System.Core is an implicit reference
if (!noStdLib) {
@@ -787,13 +871,13 @@ namespace MonoDevelop.Projects
}
}
- protected internal override void OnSave (IProgressMonitor monitor)
+ protected internal override Task OnSave (ProgressMonitor monitor)
{
// Make sure the fx version is sorted out before saving
- // to avoid changes in project references while saving
+ // to avoid changes in project references while saving
if (targetFramework == null)
targetFramework = Runtime.SystemAssemblyService.GetTargetFramework (GetDefaultTargetFrameworkForFormat (FileFormat));
- base.OnSave (monitor);
+ return base.OnSave (monitor);
}
IDotNetLanguageBinding FindLanguage (string name)
@@ -839,7 +923,7 @@ namespace MonoDevelop.Projects
{
if (base.CheckNeedsBuild (configuration))
return true;
-
+
// base.CheckNeedsBuild() checks Project references, but not Assembly, Package, or Custom.
DateTime mtime = GetLastBuildTime (configuration);
foreach (ProjectReference pref in References) {
@@ -875,11 +959,11 @@ namespace MonoDevelop.Projects
&& String.Compare (Path.GetExtension (file.FilePath), ".resx", StringComparison.OrdinalIgnoreCase) == 0
&& MD1DotNetProjectHandler.IsResgenRequired (file.FilePath, config.IntermediateOutputDirectory.Combine (file.ResourceId)));
}
-
+
protected internal override DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
{
var outputBuildTime = base.OnGetLastBuildTime (configuration);
-
+
//if the debug file is newer than the output file, use that as the build time
var conf = (DotNetProjectConfiguration) GetConfiguration (configuration);
if (GeneratesDebugInfoFile && conf != null && conf.DebugMode) {
@@ -896,7 +980,7 @@ namespace MonoDevelop.Projects
}
return outputBuildTime;
}
-
+
public IList<string> GetUserAssemblyPaths (ConfigurationSelector configuration)
{
if (ParentSolution == null)
@@ -908,7 +992,12 @@ namespace MonoDevelop.Projects
.Where (d => !string.IsNullOrEmpty (d)).ToList ();
}
- protected virtual ExecutionCommand CreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration)
+ public ExecutionCommand CreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration)
+ {
+ return ProjectExtension.OnCreateExecutionCommand (configSel, configuration);
+ }
+
+ internal protected virtual ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration)
{
DotNetExecutionCommand cmd = new DotNetExecutionCommand (configuration.CompiledOutputName);
cmd.Arguments = configuration.CommandLineParameters;
@@ -919,7 +1008,7 @@ namespace MonoDevelop.Projects
return cmd;
}
- protected internal override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
{
DotNetProjectConfiguration config = (DotNetProjectConfiguration) GetConfiguration (configuration);
if (config == null)
@@ -931,10 +1020,11 @@ namespace MonoDevelop.Projects
return (compileTarget == CompileTarget.Exe || compileTarget == CompileTarget.WinExe) && context.ExecutionHandler.CanExecute (cmd);
}
- protected internal override List<FilePath> OnGetItemFiles (bool includeReferencedFiles)
+ protected override IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
{
- List<FilePath> col = base.OnGetItemFiles (includeReferencedFiles);
+ var baseFiles = base.OnGetItemFiles (includeReferencedFiles);
if (includeReferencedFiles) {
+ List<FilePath> col = new List<FilePath> ();
foreach (ProjectReference pref in References) {
if (pref.ReferenceType == ReferenceType.Assembly) {
foreach (var f in pref.GetReferencedFileNames (DefaultConfiguration.Selector))
@@ -945,10 +1035,20 @@ namespace MonoDevelop.Projects
if (c.SignAssembly)
col.Add (c.AssemblyKeyFile);
}
+ baseFiles = baseFiles.Concat (col);
}
- return col;
+ return baseFiles;
+ }
+
+ internal Task<BuildResult> Compile (ProgressMonitor monitor, BuildData buildData)
+ {
+ return ProjectExtension.OnCompile (monitor, buildData);
}
+ protected virtual Task<BuildResult> OnCompile (ProgressMonitor monitor, BuildData buildData)
+ {
+ return MD1DotNetProjectHandler.Compile (monitor, this, buildData);
+ }
public override bool IsCompileable (string fileName)
{
@@ -979,7 +1079,7 @@ namespace MonoDevelop.Projects
string defaultNmspc = !string.IsNullOrEmpty (defaultNamespace)
? defaultNamespace
: SanitisePotentialNamespace (project.Name) ?? "Application";
-
+
if (string.IsNullOrEmpty (fileName)) {
return defaultNmspc;
}
@@ -1088,22 +1188,6 @@ namespace MonoDevelop.Projects
return BuildAction.DotNetCommonActions;
}
- internal override void SetItemHandler (ISolutionItemHandler handler)
- {
- if (ProjectExtensionUtil.GetItemHandler (this) == null) {
- // Initial assignment of the item handler
- base.SetItemHandler (handler);
- return;
- }
- IResourceHandler rh = ResourceHandler;
-
- base.SetItemHandler (handler);
- resourceHandler = null;
- // A change in the file format may imply a change in the resource naming policy.
- // Make sure that the resource Id don't change.
- MigrateResourceIds (rh, ResourceHandler);
- }
-
protected override void OnEndLoad ()
{
// The resource handler policy may have changed after loading, so reset any
@@ -1112,7 +1196,7 @@ namespace MonoDevelop.Projects
// Just after loading, the resource Ids are using the file format's policy.
// They have to be converted to the new policy
- IResourceHandler handler = ItemHandler as IResourceHandler;
+ IResourceHandler handler = GetService<IResourceHandler> ();
if (handler != null)
MigrateResourceIds (handler, ResourceHandler);
@@ -1172,13 +1256,13 @@ namespace MonoDevelop.Projects
internal void NotifyReferenceRemovedFromProject (ProjectReference reference)
{
NotifyModified ("References");
- OnReferenceRemovedFromProject (new ProjectReferenceEventArgs (this, reference));
+ ProjectExtension.OnReferenceRemovedFromProject (new ProjectReferenceEventArgs (this, reference));
}
internal void NotifyReferenceAddedToProject (ProjectReference reference)
{
NotifyModified ("References");
- OnReferenceAddedToProject (new ProjectReferenceEventArgs (this, reference));
+ ProjectExtension.OnReferenceAddedToProject (new ProjectReferenceEventArgs (this, reference));
}
protected virtual void OnReferenceRemovedFromProject (ProjectReferenceEventArgs e)
@@ -1205,7 +1289,7 @@ namespace MonoDevelop.Projects
CheckReferenceChange (ei.FileName);
}
- protected override void DoExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ protected async override Task DoExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
DotNetProjectConfiguration dotNetProjectConfig = GetConfiguration (configuration) as DotNetProjectConfiguration;
monitor.Log.WriteLine (GettextCatalog.GetString ("Running {0} ...", dotNetProjectConfig.CompiledOutputName));
@@ -1213,8 +1297,6 @@ namespace MonoDevelop.Projects
IConsole console = dotNetProjectConfig.ExternalConsole
? context.ExternalConsoleFactory.CreateConsole (!dotNetProjectConfig.PauseConsoleOutput)
: context.ConsoleFactory.CreateConsole (!dotNetProjectConfig.PauseConsoleOutput);
-
- AggregatedOperationMonitor aggregatedOperationMonitor = new AggregatedOperationMonitor (monitor);
try {
try {
@@ -1227,14 +1309,16 @@ namespace MonoDevelop.Projects
return;
}
- IProcessAsyncOperation asyncOp = context.ExecutionHandler.Execute (executionCommand, console);
- aggregatedOperationMonitor.AddOperation (asyncOp);
- asyncOp.WaitForCompleted ();
+ ProcessAsyncOperation asyncOp = context.ExecutionHandler.Execute (executionCommand, console);
+ var stopper = monitor.CancellationToken.Register (asyncOp.Cancel);
+
+ await asyncOp.Task;
+
+ stopper.Dispose ();
monitor.Log.WriteLine (GettextCatalog.GetString ("The application exited with code: {0}", asyncOp.ExitCode));
} finally {
console.Dispose ();
- aggregatedOperationMonitor.Dispose ();
}
} catch (Exception ex) {
LoggingService.LogError (string.Format ("Cannot execute \"{0}\"", dotNetProjectConfig.CompiledOutputName), ex);
@@ -1242,32 +1326,158 @@ namespace MonoDevelop.Projects
}
}
- public void AddImportIfMissing (string name, string condition)
+
+ protected override void OnReadProjectHeader (ProgressMonitor monitor, MSBuildProject msproject)
{
- importsAdded.Add (new DotNetProjectImport (name, condition));
+ base.OnReadProjectHeader (monitor, msproject);
+
+ compileTarget = msproject.EvaluatedProperties.GetValue<CompileTarget> ("OutputType");
+ defaultNamespace = msproject.EvaluatedProperties.GetValue ("RootNamespace", string.Empty);
+ usePartialTypes = msproject.EvaluatedProperties.GetValue ("UsePartialTypes", true);
+
+ string frameworkIdentifier = msproject.EvaluatedProperties.GetValue ("TargetFrameworkIdentifier");
+ string frameworkVersion = msproject.EvaluatedProperties.GetValue ("TargetFrameworkVersion");
+ string frameworkProfile = msproject.EvaluatedProperties.GetValue ("TargetFrameworkProfile");
+
+ //determine the default target framework from the project type's default
+ //overridden by the components in the project
+ var def = GetDefaultTargetFrameworkForFormat (GetFileFormat (GetToolsFormat ()));
+ var targetFx = new TargetFrameworkMoniker (
+ string.IsNullOrEmpty (frameworkIdentifier)? def.Identifier : frameworkIdentifier,
+ string.IsNullOrEmpty (frameworkVersion)? def.Version : frameworkVersion,
+ string.IsNullOrEmpty (frameworkProfile)? def.Profile : frameworkProfile);
+
+
+ string fx = ExtendedProperties ["InternalTargetFrameworkVersion"] as string;
+ if (!string.IsNullOrEmpty (fx)) {
+ targetFx = TargetFrameworkMoniker.Parse (fx);
+ ExtendedProperties.Remove ("InternalTargetFrameworkVersion");
+ }
+
+ TargetFramework = Runtime.SystemAssemblyService.GetTargetFramework (targetFx);
}
- public void RemoveImport (string name)
+ protected override void OnWriteProjectHeader (ProgressMonitor monitor, MSBuildProject msproject)
{
- importsRemoved.Add (new DotNetProjectImport (name));
+ base.OnWriteProjectHeader (monitor, msproject);
+
+ IMSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup ();
+
+ globalGroup.SetValue ("OutputType", compileTarget);
+ globalGroup.SetValue ("RootNamespace", defaultNamespace, string.Empty);
+ globalGroup.SetValue ("UsePartialTypes", usePartialTypes, true);
}
- List <DotNetProjectImport> importsAdded = new List<DotNetProjectImport> ();
+ protected override void OnWriteProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ base.OnWriteProject (monitor, msproject);
+
+ var toolsFormat = GetToolsFormat ();
+ var moniker = TargetFramework.Id;
+ bool supportsMultipleFrameworks = toolsFormat.SupportsMonikers || toolsFormat.SupportedFrameworks.Length > 0;
+ var def = GetDefaultTargetFrameworkForFormat (GetFileFormat (toolsFormat));
+
+ IMSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup ();
- internal IList<DotNetProjectImport> ImportsAdded {
- get { return importsAdded; }
+ // If the format only supports one fx version, or the version is the default, there is no need to store it.
+ // However, is there is already a value set, do not remove it.
+ if (supportsMultipleFrameworks) {
+ globalGroup.SetValue ("TargetFrameworkVersion", "v" + moniker.Version, "v" + def.Version, true);
+ }
+
+ if (toolsFormat.SupportsMonikers) {
+ globalGroup.SetValue ("TargetFrameworkIdentifier", moniker.Identifier, def.Identifier, true);
+ globalGroup.SetValue ("TargetFrameworkProfile", moniker.Profile, def.Profile, true);
+ }
}
- List <DotNetProjectImport> importsRemoved = new List<DotNetProjectImport> ();
+ protected override void OnWriteConfiguration (ProgressMonitor monitor, ProjectConfiguration config, IMSBuildPropertySet pset)
+ {
+ base.OnWriteConfiguration (monitor, config, pset);
+ if (pset.Project.IsNewProject)
+ pset.SetValue ("ErrorReport", "prompt");
+
+ }
- internal IList<DotNetProjectImport> ImportsRemoved {
- get { return importsRemoved; }
+ FileFormat GetFileFormat (MSBuildFileFormat fmt)
+ {
+ return new FileFormat (fmt, fmt.Id, fmt.Name);
}
- public void ImportsSaved ()
+ internal class DefaultDotNetProjectExtension: DotNetProjectExtension
{
- importsAdded.Clear ();
- importsRemoved.Clear ();
+ internal protected override bool IsLibraryBasedProjectType {
+ get {
+ return false;
+ }
+ }
+
+ internal protected override bool GeneratesDebugInfoFile {
+ get {
+ return true;
+ }
+ }
+
+ internal protected override bool SupportsPartialTypes {
+ get {
+ return Project.SupportsPartialTypes;
+ }
+ }
+
+
+ internal protected override bool OnGetCanReferenceProject (DotNetProject targetProject, out string reason)
+ {
+ return Project.CheckCanReferenceProject (targetProject, out reason);
+ }
+
+ internal protected override string OnGetDefaultTargetPlatform (ProjectCreateInformation projectCreateInfo)
+ {
+ return Project.OnGetDefaultTargetPlatform (projectCreateInfo);
+ }
+
+ internal protected override IEnumerable<string> OnGetReferencedAssemblies (ConfigurationSelector configuration, bool includeProjectReferences)
+ {
+ return Project.OnGetReferencedAssemblies (configuration, includeProjectReferences);
+ }
+
+ internal protected override ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration)
+ {
+ return Project.OnCreateExecutionCommand (configSel, configuration);
+ }
+
+ internal protected override void OnReferenceRemovedFromProject (ProjectReferenceEventArgs e)
+ {
+ Project.OnReferenceRemovedFromProject (e);
+ }
+
+ internal protected override void OnReferenceAddedToProject (ProjectReferenceEventArgs e)
+ {
+ Project.OnReferenceAddedToProject (e);
+ }
+
+ internal protected override Task<BuildResult> OnCompile (ProgressMonitor monitor, BuildData buildData)
+ {
+ return Project.OnCompile (monitor, buildData);
+ }
+
+ #region Framework management
+
+ internal protected override TargetFrameworkMoniker OnGetDefaultTargetFrameworkId ()
+ {
+ return Project.OnGetDefaultTargetFrameworkId ();
+ }
+
+ internal protected override TargetFrameworkMoniker OnGetDefaultTargetFrameworkForFormat (FileFormat format)
+ {
+ return Project.OnGetDefaultTargetFrameworkForFormat (format);
+ }
+
+ internal protected override bool OnGetSupportsFramework (TargetFramework framework)
+ {
+ return Project.OnSupportsFramework (framework);
+ }
+
+ #endregion
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectBinding.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectBinding.cs
deleted file mode 100644
index e2e26591cb..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectBinding.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-// DotNetProjectBinding.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.IO;
-using System.Xml;
-using MonoDevelop.Core.Serialization;
-using MonoDevelop.Core;
-
-namespace MonoDevelop.Projects
-{
- public class DotNetProjectBinding : IProjectBinding
- {
- public virtual string Name {
- get { return "DotNet"; }
- }
-
- public Project CreateProject (ProjectCreateInformation info, XmlElement projectOptions)
- {
- string lang = projectOptions.GetAttribute ("language");
- return CreateProject (lang, info, projectOptions);
- }
-
- protected virtual DotNetProject CreateProject (string languageName, ProjectCreateInformation info, XmlElement projectOptions)
- {
- return new DotNetAssemblyProject (languageName, info, projectOptions);
- }
-
- public Project CreateSingleFileProject (string file)
- {
- IDotNetLanguageBinding binding = LanguageBindingService.GetBindingPerFileName (file) as IDotNetLanguageBinding;
- if (binding != null) {
- ProjectCreateInformation info = new ProjectCreateInformation ();
- info.ProjectName = Path.GetFileNameWithoutExtension (file);
- info.SolutionPath = Path.GetDirectoryName (file);
- info.ProjectBasePath = Path.GetDirectoryName (file);
- Project project = CreateProject (binding.Language, info, null);
- project.Files.Add (new ProjectFile (file));
- return project;
- }
- return null;
- }
-
- public bool CanCreateSingleFileProject (string file)
- {
- IDotNetLanguageBinding binding = LanguageBindingService.GetBindingPerFileName (file) as IDotNetLanguageBinding;
- return binding != null;
- }
-
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs
index ed6bb65fa5..5d359650c8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectConfiguration.cs
@@ -35,6 +35,7 @@ using MonoDevelop.Core.Serialization;
using MonoDevelop.Core.Assemblies;
using MonoDevelop.Core.StringParsing;
using System.Collections.Generic;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
@@ -47,14 +48,10 @@ namespace MonoDevelop.Projects
public class DotNetProjectConfiguration: ProjectConfiguration
{
- [MonoDevelop.Projects.Formats.MSBuild.MergeToProject]
- [ItemProperty ("AssemblyName")]
string assembly;
-
- ConfigurationParameters compilationParameters;
-
string sourcePath;
-
+ DotNetCompilerParameters compilationParameters;
+
public DotNetProjectConfiguration ()
{
}
@@ -63,32 +60,49 @@ namespace MonoDevelop.Projects
{
}
- [MonoDevelop.Projects.Formats.MSBuild.MergeToProject]
- [ItemProperty("SignAssembly", DefaultValue = false)]
+ internal protected override void Read (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ base.Read (pset, format);
+
+ assembly = pset.GetValue ("AssemblyName");
+ signAssembly = pset.GetValue<bool> ("SignAssembly");
+ delaySign = pset.GetValue<bool> ("DelaySign");
+ assemblyKeyFile = pset.GetPathValue ("AssemblyOriginatorKeyFile");
+ if (string.IsNullOrEmpty (assemblyKeyFile))
+ assemblyKeyFile = pset.GetPathValue ("AssemblyKeyFile");
+ if (compilationParameters != null)
+ ((IMSBuildDataObject)compilationParameters).Read (pset, format);
+ }
+
+ internal protected override void Write (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ base.Write (pset, format);
+ pset.SetValue ("AssemblyName", assembly, mergeToMainGroup: true);
+ pset.SetValue ("SignAssembly", signAssembly, defaultValue:false, mergeToMainGroup: true);
+ pset.SetValue ("DelaySign", delaySign, defaultValue:false, mergeToMainGroup:true);
+ pset.SetValue ("AssemblyOriginatorKeyFile", assemblyKeyFile, mergeToMainGroup:true);
+ if (compilationParameters != null)
+ ((IMSBuildDataObject)compilationParameters).Write (pset, format);
+ }
+
private bool signAssembly = false;
public bool SignAssembly {
get { return signAssembly; }
set { signAssembly = value; }
}
- [MonoDevelop.Projects.Formats.MSBuild.MergeToProject]
- [ItemProperty("DelaySign", DefaultValue = false)]
private bool delaySign = false;
public bool DelaySign {
get { return delaySign; }
set { delaySign = value; }
}
- [MonoDevelop.Projects.Formats.MSBuild.MergeToProject]
- [ProjectPathItemProperty("AssemblyKeyFile", ReadOnly=true)]
internal string OldAssemblyKeyFile {
set { assemblyKeyFile = value; }
}
- [MonoDevelop.Projects.Formats.MSBuild.MergeToProject]
- [ProjectPathItemProperty("AssemblyOriginatorKeyFile", DefaultValue = "")]
- private string assemblyKeyFile = "";
- public string AssemblyKeyFile {
+ private FilePath assemblyKeyFile = FilePath.Empty;
+ public FilePath AssemblyKeyFile {
get { return assemblyKeyFile; }
set { assemblyKeyFile = value; }
}
@@ -149,8 +163,7 @@ namespace MonoDevelop.Projects
}
}
- [ItemProperty ("CodeGeneration")]
- public ConfigurationParameters CompilationParameters {
+ public DotNetCompilerParameters CompilationParameters {
get { return compilationParameters; }
set {
compilationParameters = value;
@@ -159,16 +172,6 @@ namespace MonoDevelop.Projects
}
}
- public ProjectParameters ProjectParameters {
- get {
- DotNetProject dnp = ParentItem as DotNetProject;
- if (dnp != null)
- return dnp.LanguageParameters;
- else
- return null;
- }
- }
-
public FilePath CompiledOutputName {
get {
FilePath fullPath = OutputDirectory.Combine (OutputAssembly);
@@ -206,7 +209,7 @@ namespace MonoDevelop.Projects
}
}
- public class UnknownCompilationParameters: ConfigurationParameters, IExtendedDataItem
+ public class UnknownCompilationParameters: DotNetCompilerParameters, IExtendedDataItem
{
readonly Hashtable table = new Hashtable ();
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectExtension.cs
new file mode 100644
index 0000000000..09f2a6b871
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectExtension.cs
@@ -0,0 +1,132 @@
+//
+// DotNetProjectExtension.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using MonoDevelop.Core.Assemblies;
+using MonoDevelop.Core.Execution;
+using MonoDevelop.Core;
+using System.Threading.Tasks;
+
+namespace MonoDevelop.Projects
+{
+ public class DotNetProjectExtension: ProjectExtension
+ {
+ #region Project properties
+
+ DotNetProjectExtension next;
+
+ internal protected override void InitializeChain (ChainedExtension next)
+ {
+ base.InitializeChain (next);
+ this.next = FindNextImplementation<DotNetProjectExtension> (next);
+ }
+
+ internal protected override bool SupportsObject (WorkspaceObject item)
+ {
+ return base.SupportsObject (item) && (item is DotNetProject);
+ }
+
+ new public DotNetProject Project {
+ get { return (DotNetProject)base.Item; }
+ }
+
+
+ internal protected virtual bool IsLibraryBasedProjectType {
+ get {
+ return next.IsLibraryBasedProjectType;
+ }
+ }
+
+ internal protected virtual bool GeneratesDebugInfoFile {
+ get {
+ return next.GeneratesDebugInfoFile;
+ }
+ }
+
+ internal protected virtual bool SupportsPartialTypes {
+ get {
+ return next.SupportsPartialTypes;
+ }
+ }
+
+ #endregion
+
+ internal protected virtual bool OnGetCanReferenceProject (DotNetProject targetProject, out string reason)
+ {
+ return next.OnGetCanReferenceProject (targetProject, out reason);
+ }
+
+ internal protected virtual string OnGetDefaultTargetPlatform (ProjectCreateInformation projectCreateInfo)
+ {
+ return next.OnGetDefaultTargetPlatform (projectCreateInfo);
+ }
+
+ internal protected virtual IEnumerable<string> OnGetReferencedAssemblies (ConfigurationSelector configuration, bool includeProjectReferences)
+ {
+ return next.OnGetReferencedAssemblies (configuration, includeProjectReferences);
+ }
+
+ internal protected virtual ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration)
+ {
+ return next.OnCreateExecutionCommand (configSel, configuration);
+ }
+
+ internal protected virtual void OnReferenceRemovedFromProject (ProjectReferenceEventArgs e)
+ {
+ next.OnReferenceRemovedFromProject (e);
+ }
+
+ internal protected virtual void OnReferenceAddedToProject (ProjectReferenceEventArgs e)
+ {
+ next.OnReferenceAddedToProject (e);
+ }
+
+ #region Framework management
+
+ internal protected virtual TargetFrameworkMoniker OnGetDefaultTargetFrameworkId ()
+ {
+ return next.OnGetDefaultTargetFrameworkId ();
+ }
+
+ internal protected virtual TargetFrameworkMoniker OnGetDefaultTargetFrameworkForFormat (FileFormat format)
+ {
+ return next.OnGetDefaultTargetFrameworkForFormat (format);
+ }
+
+ internal protected virtual bool OnGetSupportsFramework (TargetFramework framework)
+ {
+ return next.OnGetSupportsFramework (framework);
+ }
+
+ internal protected virtual Task<BuildResult> OnCompile (ProgressMonitor monitor, BuildData buildData)
+ {
+ return next.OnCompile (monitor, buildData);
+ }
+
+ #endregion
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ExtensionChain.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ExtensionChain.cs
new file mode 100644
index 0000000000..9916adc7bd
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ExtensionChain.cs
@@ -0,0 +1,69 @@
+//
+// ExtensionChain.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Projects
+{
+ public class ExtensionChain
+ {
+ ChainedExtension first;
+ Dictionary<Type,ChainedExtension> chains = new Dictionary<Type, ChainedExtension> ();
+
+ public static ExtensionChain Create<T> (T[] extensions) where T:ChainedExtension
+ {
+ for (int n = extensions.Length - 2; n >= 0; n--)
+ extensions [n].Init (extensions [n + 1]);
+ return new ExtensionChain {
+ first = extensions[0]
+ };
+ }
+
+ public T GetExtension<T> () where T:ChainedExtension
+ {
+ ChainedExtension e;
+ if (!chains.TryGetValue (typeof(T), out e)) {
+ chains [typeof(T)] = e = ChainedExtension.FindNextImplementation<T> (first);
+ }
+ return (T)e;
+ }
+
+ public IEnumerable<ChainedExtension> GetAllExtensions ()
+ {
+ var e = first;
+ while (e != null) {
+ yield return e;
+ e = e.Next;
+ }
+ }
+
+ public void Dispose ()
+ {
+ first.DisposeChain ();
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProject.cs
index 9e14d17bb6..7e324914a0 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProject.cs
@@ -49,9 +49,9 @@ namespace MonoDevelop.Projects
return conf;
}
- public override IEnumerable<string> GetProjectTypes ()
+ protected override void OnGetProjectTypes (HashSet<string> types)
{
- yield return "GenericProject";
+ types.Add ("GenericProject");
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProjectBinding.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProjectBinding.cs
deleted file mode 100644
index a0adbabee8..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/GenericProjectBinding.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-// MakefileProjectBinding.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.IO;
-using System.Xml;
-using MonoDevelop.Core.Serialization;
-using MonoDevelop.Core;
-using MonoDevelop.Projects;
-
-namespace MonoDevelop.Projects
-{
- public class GenericProjectBinding : IProjectBinding
- {
- public virtual string Name {
- get { return "GenericProject"; }
- }
-
- public Project CreateProject (ProjectCreateInformation info, XmlElement projectOptions)
- {
- return new GenericProject (info, projectOptions);
- }
-
- public Project CreateSingleFileProject (string file)
- {
- return null;
- }
-
- public bool CanCreateSingleFileProject (string file)
- {
- return false;
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IBuildTarget.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IBuildTarget.cs
index 46f53edd81..bc882c60d3 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IBuildTarget.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IBuildTarget.cs
@@ -29,19 +29,17 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
- public interface IBuildTarget: IWorkspaceObject
+ public interface IBuildTarget
{
- BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration);
- bool SupportsTarget (string target);
- void Execute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration);
+ Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector configuration, bool buildReferencedTargets = false);
+ Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration);
+ Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration);
bool CanExecute (ExecutionContext context, ConfigurationSelector configuration);
bool NeedsBuilding (ConfigurationSelector configuration);
- void SetNeedsBuilding (bool needsBuilding, ConfigurationSelector configuration);
-
-// ReadOnlyCollection<string> GetConfigurations ();
-// event EventHandler ConfigurationsChanged;
+ string Name { get; }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IDotNetLanguageBinding.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IDotNetLanguageBinding.cs
index 618219d4a3..9b30606afb 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IDotNetLanguageBinding.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IDotNetLanguageBinding.cs
@@ -38,10 +38,9 @@ namespace MonoDevelop.Projects
get;
}
- ConfigurationParameters CreateCompilationParameters (XmlElement projectOptions);
- ProjectParameters CreateProjectParameters (XmlElement projectOptions);
+ DotNetCompilerParameters CreateCompilationParameters (XmlElement projectOptions);
- BuildResult Compile (ProjectItemCollection items, DotNetProjectConfiguration configuration, ConfigurationSelector configSelector, IProgressMonitor monitor);
+ BuildResult Compile (ProjectItemCollection items, DotNetProjectConfiguration configuration, ConfigurationSelector configSelector, ProgressMonitor monitor);
ClrVersion[] GetSupportedClrVersions ();
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectParameters.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IMSBuildDataObject.cs
index 013b99f441..2c94b3c395 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectParameters.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IMSBuildDataObject.cs
@@ -1,21 +1,21 @@
-//
-// DotNetProjectParameters.cs
-//
+//
+// IProjectConfigurationData.cs
+//
// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
-//
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
-//
+//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -23,18 +23,15 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-
using System;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
- /// <summary>
- /// This is the base class for project parameter classes.
- /// </summary>
- public class DotNetProjectParameters: ProjectParameters
+ public interface IMSBuildDataObject
{
- public virtual bool DefaultNamespaceIsImplicit {
- get { return false; }
- }
+ void Read (IMSBuildPropertySet pset, MSBuildFileFormat format);
+ void Write (IMSBuildPropertySet pset, MSBuildFileFormat format);
}
}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SimpleProjectItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IProject.cs
index 633e82f83d..286b4abe95 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SimpleProjectItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IProject.cs
@@ -1,21 +1,21 @@
-//
-// SimpleProjectItem.cs
-//
+//
+// IProject.cs
+//
// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
-//
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
-//
+//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -23,15 +23,12 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-
using System;
-using MonoDevelop.Core.Serialization;
namespace MonoDevelop.Projects
{
- public class SimpleProjectItem: ProjectItem
+ public interface IProject2
{
- [ItemProperty ("Include")]
- public string Include { get; set; }
}
}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IProjectBinding.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IProjectBinding.cs
deleted file mode 100644
index 5c0ce972f9..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IProjectBinding.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-// IProjectBinding.cs
-//
-// Author:
-// Lluis Sanchez Gual
-
-//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-
-using System;
-using System.Collections;
-using System.Xml;
-
-namespace MonoDevelop.Projects
-{
- public interface IProjectBinding
- {
- /// <remarks>
- /// Returns the project type name
- /// </remarks>
- string Name { get; }
-
- /// <remarks>
- /// Creates a Project out of the given ProjetCreateInformation object.
- /// Each project binding must provide a representation of the project
- /// it 'controls'.
- /// </remarks>
- Project CreateProject (ProjectCreateInformation info, XmlElement projectOptions);
-
- /// <remarks>
- /// Creates a Project for a single source file. If the file is not
- /// valid for this project type, it must return null.
- /// </remarks>
- Project CreateSingleFileProject (string sourceFile);
-
- bool CanCreateSingleFileProject (string sourceFile);
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IPropertySet.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IPropertySet.cs
new file mode 100644
index 0000000000..56ccd1f3c8
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IPropertySet.cs
@@ -0,0 +1,49 @@
+//
+// IPropertySet.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Xml;
+using MonoDevelop.Core;
+using System.Xml.Linq;
+
+namespace MonoDevelop.Projects
+{
+ public interface IPropertySet
+ {
+
+ void SetValue (string name, string value, string defaultValue = null, bool preserveExistingCase = false, bool mergeToMainGroup = false, string condition = null, bool persist = true);
+ void SetValue (string name, XmlElement elem, bool mergeToMainGroup = false, string condition = null, bool persist = true);
+ void SetValue (string name, XElement elem, bool mergeToMainGroup = false, string condition = null, bool persist = true);
+ void SetValue (string name, FilePath value, FilePath defaultValue = default(FilePath), bool relativeToProject = true, bool mergeToMainGroup = false, string condition = null, bool persist = true);
+ void SetValue (string name, bool value, bool? defaultValue = false, bool mergeToMainGroup = false, string condition = null, bool persist = true);
+
+ string GetValue (string name, string defaultValue = null);
+ XElement GetXmlValue (string name);
+ FilePath GetPathValue (string name, FilePath defaultValue = default(FilePath), bool relativeToProject = true);
+ bool GetBoolValue (string name, bool defaultValue = false);
+
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemConfiguration.cs
index 32e1e1316e..8956f4feef 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemConfiguration.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemConfiguration.cs
@@ -32,6 +32,7 @@ using System.Collections.ObjectModel;
using MonoDevelop.Projects;
using MonoDevelop.Core.Serialization;
using MonoDevelop.Core;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
@@ -107,7 +108,7 @@ namespace MonoDevelop.Projects
public CustomCommandCollection CustomCommands {
get { return customCommands; }
}
-
+
public object Clone()
{
ItemConfiguration conf = (ItemConfiguration) Activator.CreateInstance (GetType ());
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/LanguageBindingService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/LanguageBindingService.cs
index f2823eeeb3..61b04d8b89 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/LanguageBindingService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/LanguageBindingService.cs
@@ -48,9 +48,6 @@ namespace MonoDevelop.Projects
object par = dotNetBinding.CreateCompilationParameters (null);
if (par != null)
Services.ProjectService.DataContext.IncludeType (par.GetType ());
- par = dotNetBinding.CreateProjectParameters (null);
- if (par != null)
- Services.ProjectService.DataContext.IncludeType (par.GetType ());
}
break;
case ExtensionChange.Remove:
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProjectFlavor.cs
index 7903a6152a..4a30eee279 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProjectFlavor.cs
@@ -1,20 +1,21 @@
-//
-// PortableDotNetProject.cs
-//
-// Author: Jeffrey Stedfast <jeff@xamarin.com>
-//
-// Copyright (c) 2012 Xamarin Inc.
-//
+//
+// PortableDotNetProjectFlavor.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
-//
+//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -22,57 +23,39 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-
using System;
-using System.Xml;
-using MonoDevelop.Core;
+using System.Collections.Generic;
using MonoDevelop.Core.Assemblies;
using System.Linq;
-using System.Collections.Generic;
namespace MonoDevelop.Projects
{
- public class PortableDotNetProject : DotNetProject
+ public class PortableDotNetProjectFlavor: DotNetProjectExtension
{
- public PortableDotNetProject ()
- {
- }
-
- public PortableDotNetProject (string languageName) : base (languageName)
- {
- }
-
- public PortableDotNetProject (string languageName, ProjectCreateInformation projectCreateInfo, XmlElement projectOptions)
- : base (languageName, projectCreateInfo, projectOptions)
+ internal protected override void OnGetProjectTypes (HashSet<string> types)
{
+ types.Add ("PortableDotNet");
}
- public override IEnumerable<string> GetProjectTypes ()
- {
- yield return "PortableDotNet";
- foreach (var t in base.GetProjectTypes ())
- yield return t;
- }
-
- public override bool SupportsFormat (FileFormat format)
+ internal protected override bool OnGetSupportsFormat (FileFormat format)
{
int version;
-
+
if (!format.Id.StartsWith ("MSBuild", StringComparison.Ordinal))
return false;
-
+
if (!int.TryParse (format.Id.Substring ("MSBuild".Length), out version))
return false;
-
+
return version >= 10;
}
-
- public override bool SupportsFramework (TargetFramework framework)
+
+ internal protected override bool OnGetSupportsFramework (TargetFramework framework)
{
return framework.Id.Identifier == TargetFrameworkMoniker.ID_PORTABLE;
}
-
- public override TargetFrameworkMoniker GetDefaultTargetFrameworkForFormat (FileFormat format)
+
+ internal protected override TargetFrameworkMoniker OnGetDefaultTargetFrameworkForFormat (FileFormat format)
{
// Note: This value is used only when serializing the TargetFramework to the .csproj file.
// Any component of the TargetFramework that is different from this base TargetFramework
@@ -82,19 +65,20 @@ namespace MonoDevelop.Projects
// TargetFrameworkVersion and TargetFrameworkProfile values will be serialized.
return new TargetFrameworkMoniker (".NETPortable", "1.0");
}
-
- public override TargetFrameworkMoniker GetDefaultTargetFrameworkId ()
+
+ internal protected override TargetFrameworkMoniker OnGetDefaultTargetFrameworkId ()
{
// Profile78 includes .NET 4.5+, Windows Phone 8, and Xamarin.iOS/Android, so make that our default.
// Note: see also: PortableLibrary.xpt.xml
return new TargetFrameworkMoniker (".NETPortable", "4.5", "Profile78");
}
- protected internal override IEnumerable<string> OnGetReferencedAssemblies (ConfigurationSelector configuration, bool includeProjectReferences)
+ internal protected override IEnumerable<string> OnGetReferencedAssemblies (ConfigurationSelector configuration, bool includeProjectReferences)
{
var res = base.OnGetReferencedAssemblies (configuration, includeProjectReferences);
- var asms = TargetRuntime.AssemblyContext.GetAssemblies (TargetFramework).Where (a => a.Package.IsFrameworkPackage).Select (a => a.Location);
+ var asms = Project.TargetRuntime.AssemblyContext.GetAssemblies (Project.TargetFramework).Where (a => a.Package.IsFrameworkPackage).Select (a => a.Location);
return res.Concat (asms).Distinct ();
}
}
}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
index b3bf2233e3..ce145e9c78 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
@@ -37,6 +37,14 @@ using MonoDevelop;
using MonoDevelop.Core;
using MonoDevelop.Core.Serialization;
using MonoDevelop.Projects;
+using System.Threading.Tasks;
+using MonoDevelop.Projects.Formats.MSBuild;
+using System.Xml;
+using MonoDevelop.Core.Instrumentation;
+using MonoDevelop.Core.Assemblies;
+using MonoDevelop.Projects.Extensions;
+using System.Threading;
+using Mono.Addins;
namespace MonoDevelop.Projects
@@ -48,27 +56,200 @@ namespace MonoDevelop.Projects
/// This is the base class for MonoDevelop projects. A project is a solution item which has a list of
/// source code files and which can be built to generate an output.
/// </remarks>
- [DataInclude(typeof(ProjectFile))]
- [ProjectModelDataItem(FallbackType = typeof(UnknownProject))]
- public abstract class Project : SolutionEntityItem
+ public class Project : SolutionItem
{
+ string[] flavorGuids = new string[0];
string[] buildActions;
+ MSBuildProject sourceProject;
+
+ string productVersion;
+ string schemaVersion;
+ bool modifiedInMemory;
+
+ List<string> defaultImports = new List<string> ();
protected Project ()
{
FileService.FileChanged += OnFileChanged;
+ Runtime.SystemAssemblyService.DefaultRuntimeChanged += OnDefaultRuntimeChanged;
files = new ProjectFileCollection ();
Items.Bind (files);
DependencyResolutionEnabled = true;
}
-
+
+ protected Project (params string[] flavorGuids): this()
+ {
+ this.flavorGuids = flavorGuids;
+ }
+
+ protected Project (string[] flavorIds, MSBuildProject sourceProject): this(flavorIds)
+ {
+ }
+
+ protected Project (ProjectCreateInformation projectCreateInfo, XmlElement projectOptions): this()
+ {
+ var ids = projectOptions != null ? projectOptions.GetAttribute ("flavorIds") : null;
+ if (!string.IsNullOrEmpty (ids)) {
+ this.flavorGuids = ids.Split (new [] {';'}, StringSplitOptions.RemoveEmptyEntries);
+ }
+ }
+
+ internal class CreationContext
+ {
+ static object theLock = new object ();
+ public MSBuildProject Project { get; set; }
+ public string TypeGuid { get; set; }
+
+ internal static void LockContext (MSBuildProject p, string typeGuid)
+ {
+ Monitor.Enter (theLock);
+ Current = new CreationContext ();
+ Current.Project = p;
+ Current.TypeGuid = typeGuid;
+ }
+
+ internal static void UnlockContext ()
+ {
+ Current = null;
+ Monitor.Exit (theLock);
+ }
+
+ public static CreationContext Current { get; private set; }
+ }
+
+ protected override void OnInitialize ()
+ {
+ base.OnInitialize ();
+
+ if (CreationContext.Current != null) {
+
+ if (IsExtensionChainCreated)
+ throw new InvalidOperationException ("Extension chain already created for this object");
+
+ TypeGuid = CreationContext.Current.TypeGuid;
+ this.sourceProject = CreationContext.Current.Project;
+
+ IMSBuildPropertySet globalGroup = sourceProject.GetGlobalPropertyGroup ();
+ string projectTypeGuids = globalGroup.GetValue ("ProjectTypeGuids");
+
+ if (projectTypeGuids != null) {
+ var subtypeGuids = new List<string> ();
+ foreach (string guid in projectTypeGuids.Split (';')) {
+ string sguid = guid.Trim ();
+ if (sguid.Length > 0 && string.Compare (sguid, CreationContext.Current.TypeGuid, StringComparison.OrdinalIgnoreCase) != 0)
+ subtypeGuids.Add (guid);
+ }
+ flavorGuids = subtypeGuids.ToArray ();
+ }
+ }
+ }
+
+ protected override void OnExtensionChainInitialized ()
+ {
+ base.OnExtensionChainInitialized ();
+ if (CreationContext.Current != null)
+ FileName = CreationContext.Current.Project.FileName;
+ }
+
+ void OnDefaultRuntimeChanged (object o, EventArgs args)
+ {
+ // If the default runtime changes, the project builder for this project may change
+ // so it has to be created again.
+ CleanupProjectBuilder ();
+ }
+
+ public IEnumerable<string> FlavorGuids {
+ get { return flavorGuids; }
+ }
+
+ public List<string> DefaultImports {
+ get { return defaultImports; }
+ }
+
+ public string ToolsVersion { get; private set; }
+
+ internal bool CheckAllFlavorsSupported ()
+ {
+ return FlavorGuids.All (g => ProjectExtension.SupportsFlavor (g));
+ }
+
+ ProjectExtension projectExtension;
+ ProjectExtension ProjectExtension {
+ get {
+ if (projectExtension == null)
+ projectExtension = ExtensionChain.GetExtension<ProjectExtension> ();
+ return projectExtension;
+ }
+ }
+
+ /// <summary>Whether to use the MSBuild engine by default.</summary>
+ internal bool UseMSBuildEngineByDefault { get; set; }
+
+ /// <summary>Forces the MSBuild engine to be used.</summary>
+ internal bool RequireMSBuildEngine { get; set; }
+
+ protected override void OnModified (SolutionItemModifiedEventArgs args)
+ {
+ if (!Loading)
+ modifiedInMemory = true;
+ base.OnModified (args);
+ }
+
+ protected override Task OnLoad (ProgressMonitor monitor)
+ {
+ MSBuildProject p = sourceProject;
+ sourceProject = null;
+
+ return Task.Factory.StartNew (delegate {
+ if (p == null)
+ p = MSBuildProject.LoadAsync (FileName).Result;
+ IMSBuildPropertySet globalGroup = p.GetGlobalPropertyGroup ();
+ // Avoid crash if there is not global group
+ if (globalGroup == null)
+ p.AddNewPropertyGroup (false);
+
+ try {
+ ProjectExtensionUtil.BeginLoadOperation ();
+ ReadProject (monitor, p);
+ } finally {
+ ProjectExtensionUtil.EndLoadOperation ();
+ }
+ });
+ }
+
+ internal protected override Task OnSave (ProgressMonitor monitor)
+ {
+ modifiedInMemory = false;
+
+ return Task.Factory.StartNew (delegate {
+ var msproject = WriteProject (monitor);
+ if (msproject == null)
+ return;
+
+ // Don't save the file to disk if the content did not change
+ msproject.Save (FileName);
+
+ if (projectBuilder != null)
+ projectBuilder.Refresh ();
+ });
+ }
+
+ protected override IEnumerable<WorkspaceObjectExtension> CreateDefaultExtensions ()
+ {
+ return base.CreateDefaultExtensions ().Concat (Enumerable.Repeat (new DefaultMSBuildProjectExtension (), 1));
+ }
+
+ internal protected override IEnumerable<string> GetItemTypeGuids ()
+ {
+ return base.GetItemTypeGuids ().Concat (flavorGuids);
+ }
+
/// <summary>
/// Description of the project.
/// </summary>
- [ItemProperty("Description", DefaultValue = "")]
private string description = "";
public string Description {
- get { return description; }
+ get { return description ?? ""; }
set {
description = value;
NotifyModified ("Description");
@@ -86,7 +267,7 @@ namespace MonoDevelop.Projects
/// </param>
public virtual bool IsCompileable (string fileName)
{
- return false;
+ return ProjectExtension.OnGetIsCompileable (fileName);
}
/// <summary>
@@ -97,7 +278,6 @@ namespace MonoDevelop.Projects
}
private ProjectFileCollection files;
- [ProjectPathItemProperty ("BaseIntermediateOutputPath")]
FilePath baseIntermediateOutputPath;
public virtual FilePath BaseIntermediateOutputPath {
@@ -129,7 +309,31 @@ namespace MonoDevelop.Projects
/// <summary>
/// Gets the project type and its base types.
/// </summary>
- public abstract IEnumerable<string> GetProjectTypes ();
+ public IEnumerable<string> GetProjectTypes ()
+ {
+ var types = new HashSet<string> ();
+ ProjectExtension.OnGetProjectTypes (types);
+ return types;
+ }
+
+ protected virtual void OnGetProjectTypes (HashSet<string> types)
+ {
+ }
+
+ public bool HasFlavor<T> ()
+ {
+ return GetService (typeof(T)) != null;
+ }
+
+ public T GetFlavor<T> () where T:ProjectExtension
+ {
+ return (T) GetService (typeof(T));
+ }
+
+ internal IEnumerable<ProjectExtension> GetFlavors ()
+ {
+ return ExtensionChain.GetAllExtensions ().OfType<ProjectExtension> ();
+ }
/// <summary>
/// Gets or sets the icon of the project.
@@ -138,10 +342,15 @@ namespace MonoDevelop.Projects
/// The stock icon.
/// </value>
public virtual IconId StockIcon {
- get { return stockIcon; }
+ get {
+ if (stockIcon != null)
+ return stockIcon.Value;
+ else
+ return ProjectExtension.StockIcon;
+ }
set { this.stockIcon = value; NotifyModified ("StockIcon"); }
}
- IconId stockIcon = "md-project";
+ IconId? stockIcon;
/// <summary>
/// List of languages that this project supports
@@ -150,7 +359,7 @@ namespace MonoDevelop.Projects
/// The identifiers of the supported languages.
/// </value>
public virtual string[] SupportedLanguages {
- get { return new String[] { "" }; }
+ get { return ProjectExtension.SupportedLanguages; }
}
/// <summary>
@@ -164,9 +373,60 @@ namespace MonoDevelop.Projects
/// </param>
public virtual string GetDefaultBuildAction (string fileName)
{
- return IsCompileable (fileName) ? BuildAction.Compile : BuildAction.None;
+ return ProjectExtension.OnGetDefaultBuildAction (fileName);
}
-
+
+ public string GetDefaultResourceId (ProjectFile projectFile)
+ {
+ return ProjectExtension.OnGetDefaultResourceId (projectFile);
+ }
+
+ protected virtual string OnGetDefaultResourceId (ProjectFile projectFile)
+ {
+ return MSBuildResourceHandler.Instance.GetDefaultResourceId (projectFile);
+ }
+
+ internal ProjectItem CreateProjectItem (IMSBuildItemEvaluated item)
+ {
+ return ProjectExtension.OnCreateProjectItem (item);
+ }
+
+ protected virtual ProjectItem OnCreateProjectItem (IMSBuildItemEvaluated item)
+ {
+ if (item.Name == "Folder")
+ return new ProjectFile ();
+
+ // Unknown item. Must be a file.
+ if (!string.IsNullOrEmpty (item.Include) && !UnsupportedItems.Contains (item.Name) && IsValidFile (item.Include))
+ return new ProjectFile ();
+
+ return new UnknownProjectItem (item.Name, item.Include);
+ }
+
+ bool IsValidFile (string path)
+ {
+ // If it is an absolute uri, it's not a valid file
+ try {
+ if (Uri.IsWellFormedUriString (path, UriKind.Absolute)) {
+ var f = new Uri (path);
+ return f.Scheme == "file";
+ }
+ } catch {
+ // Old mono versions may crash in IsWellFormedUriString if the path
+ // is not an uri.
+ }
+ return true;
+ }
+
+ // Items generated by VS but which MD is not using and should be ignored
+
+ internal static readonly IList<string> UnsupportedItems = new string[] {
+ "BootstrapperFile", "AppDesigner", "WebReferences", "WebReferenceUrl", "Service",
+ "ProjectReference", "Reference", // Reference elements are included here because they are special-cased for DotNetProject, and they are unsupported in other types of projects
+ "InternalsVisibleTo",
+ "InternalsVisibleToTest"
+ };
+
/// <summary>
/// Gets a project file.
/// </summary>
@@ -255,7 +515,7 @@ namespace MonoDevelop.Projects
/// </summary>
protected virtual IEnumerable<string> GetStandardBuildActions ()
{
- return BuildAction.StandardActions;
+ return ProjectExtension.OnGetStandardBuildActions ();
}
/// <summary>
@@ -263,25 +523,244 @@ namespace MonoDevelop.Projects
/// </summary>
protected virtual IList<string> GetCommonBuildActions ()
{
- return BuildAction.StandardActions;
+ return ProjectExtension.OnGetCommonBuildActions ();
}
- public static Project LoadProject (string filename, IProgressMonitor monitor)
+ public override void Dispose ()
{
- Project prj = Services.ProjectService.ReadSolutionItem (monitor, filename) as Project;
- if (prj == null)
- throw new InvalidOperationException ("Invalid project file: " + filename);
+ FileService.FileChanged -= OnFileChanged;
+ Runtime.SystemAssemblyService.DefaultRuntimeChanged -= OnDefaultRuntimeChanged;
+ CleanupProjectBuilder ();
+ base.Dispose ();
+ }
- return prj;
+ /// <summary>
+ /// Runs a build or execution target.
+ /// </summary>
+ /// <returns>
+ /// The result of the operation
+ /// </returns>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='target'>
+ /// Name of the target
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to run the target
+ /// </param>
+ public Task<BuildResult> RunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ {
+ return ProjectExtension.OnRunTarget (monitor, target, configuration);
}
+ public bool SupportsTarget (string target)
+ {
+ return !IsUnsupportedProject && ProjectExtension.OnGetSupportsTarget (target);
+ }
- public override void Dispose ()
+ protected virtual bool OnGetSupportsTarget (string target)
{
- FileService.FileChanged -= OnFileChanged;
- base.Dispose ();
+ return target == "Build" || target == "Clean";
}
-
+
+ /// <summary>
+ /// Runs a build or execution target.
+ /// </summary>
+ /// <returns>
+ /// The result of the operation
+ /// </returns>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='target'>
+ /// Name of the target
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to run the target
+ /// </param>
+ /// <remarks>
+ /// Subclasses can override this method to provide a custom implementation of project operations such as
+ /// build or clean. The default implementation delegates the execution to the more specific OnBuild
+ /// and OnClean methods, or to the item handler for other targets.
+ /// </remarks>
+ internal async protected virtual Task<BuildResult> OnRunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ {
+ if (target == ProjectService.BuildTarget)
+ return await RunBuildTarget (monitor, configuration);
+ else if (target == ProjectService.CleanTarget)
+ return await RunCleanTarget (monitor, configuration);
+ return await RunMSBuildTarget (monitor, target, configuration) ?? new BuildResult ();
+ }
+
+
+ async Task<BuildResult> DoRunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ {
+ if (target == ProjectService.BuildTarget) {
+ SolutionItemConfiguration conf = GetConfiguration (configuration);
+ if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Build)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.Build, configuration)) {
+ var r = new BuildResult ();
+ r.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ return r;
+ }
+ return BuildResult.Success;
+ }
+ } else if (target == ProjectService.CleanTarget) {
+ SolutionItemConfiguration config = GetConfiguration (configuration);
+ if (config != null && config.CustomCommands.HasCommands (CustomCommandType.Clean)) {
+ if (!await config.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.Clean, configuration)) {
+ var r = new BuildResult ();
+ r.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ return r;
+ }
+ return BuildResult.Success;
+ }
+ }
+ return await OnRunTarget (monitor, target, configuration);
+ }
+
+ async Task<BuildResult> RunMSBuildTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ {
+ if (CheckUseMSBuildEngine (configuration)) {
+ LogWriter logWriter = new LogWriter (monitor.Log);
+ RemoteProjectBuilder builder = GetProjectBuilder ();
+ var configs = GetConfigurations (configuration);
+
+ MSBuildResult result = null;
+ await Task.Factory.StartNew (delegate {
+ result = builder.Run (configs, logWriter, MSBuildProjectService.DefaultMSBuildVerbosity, new[] { target }, null, null);
+ System.Runtime.Remoting.RemotingServices.Disconnect (logWriter);
+ });
+
+ var br = new BuildResult ();
+ foreach (var err in result.Errors) {
+ FilePath file = null;
+ if (err.File != null)
+ file = Path.Combine (Path.GetDirectoryName (err.ProjectFile), err.File);
+
+ if (err.IsWarning)
+ br.AddWarning (file, err.LineNumber, err.ColumnNumber, err.Code, err.Message);
+ else
+ br.AddError (file, err.LineNumber, err.ColumnNumber, err.Code, err.Message);
+ }
+ return br;
+ }
+ else {
+ CleanupProjectBuilder ();
+ if (this is DotNetProject) {
+ var handler = new MonoDevelop.Projects.Formats.MD1.MD1DotNetProjectHandler ((DotNetProject)this);
+ return await handler.RunTarget (monitor, target, configuration);
+ }
+ }
+ return null;
+ }
+
+ internal ProjectConfigurationInfo[] GetConfigurations (ConfigurationSelector configuration)
+ {
+ // Returns a list of project/configuration information for the provided item and all its references
+ List<ProjectConfigurationInfo> configs = new List<ProjectConfigurationInfo> ();
+ var c = GetConfiguration (configuration);
+ configs.Add (new ProjectConfigurationInfo () {
+ ProjectFile = FileName,
+ Configuration = c.Name,
+ Platform = GetExplicitPlatform (c)
+ });
+ foreach (var refProject in GetReferencedItems (configuration).OfType<Project> ()) {
+ var refConfig = refProject.GetConfiguration (configuration);
+ if (refConfig != null) {
+ configs.Add (new ProjectConfigurationInfo () {
+ ProjectFile = refProject.FileName,
+ Configuration = refConfig.Name,
+ Platform = GetExplicitPlatform (refConfig)
+ });
+ }
+ }
+ return configs.ToArray ();
+ }
+
+ //for some reason, MD internally handles "AnyCPU" as "", but we need to be explicit when
+ //passing it to the build engine
+ static string GetExplicitPlatform (SolutionItemConfiguration configObject)
+ {
+ if (string.IsNullOrEmpty (configObject.Platform)) {
+ return "AnyCPU";
+ }
+ return configObject.Platform;
+ }
+
+ #region Project builder management
+
+ RemoteProjectBuilder projectBuilder;
+ string lastBuildToolsVersion;
+ string lastBuildRuntime;
+ string lastFileName;
+ string lastSlnFileName;
+ object builderLock = new object ();
+
+ internal RemoteProjectBuilder GetProjectBuilder ()
+ {
+ //FIXME: we can't really have per-project runtimes, has to be per-solution
+ TargetRuntime runtime = null;
+ var ap = this as IAssemblyProject;
+ runtime = ap != null ? ap.TargetRuntime : Runtime.SystemAssemblyService.CurrentRuntime;
+
+ var sln = ParentSolution;
+ var slnFile = sln != null ? sln.FileName : null;
+
+ lock (builderLock) {
+ if (projectBuilder == null || lastBuildToolsVersion != ToolsVersion || lastBuildRuntime != runtime.Id || lastFileName != FileName || lastSlnFileName != slnFile) {
+ if (projectBuilder != null) {
+ projectBuilder.Dispose ();
+ projectBuilder = null;
+ }
+ projectBuilder = MSBuildProjectService.GetProjectBuilder (runtime, ToolsVersion, FileName, slnFile);
+ projectBuilder.Disconnected += delegate {
+ CleanupProjectBuilder ();
+ };
+ lastBuildToolsVersion = ToolsVersion;
+ lastBuildRuntime = runtime.Id;
+ lastFileName = FileName;
+ lastSlnFileName = slnFile;
+ } else if (modifiedInMemory) {
+ modifiedInMemory = false;
+ // TODO NPM
+// var p = SaveProject (new NullProgressMonitor ());
+// projectBuilder.RefreshWithContent (p.SaveToString ());
+ }
+ }
+ return projectBuilder;
+ }
+
+ void CleanupProjectBuilder ()
+ {
+ if (projectBuilder != null) {
+ projectBuilder.Dispose ();
+ projectBuilder = null;
+ }
+ }
+
+ #endregion
+
+ /// <summary>Whether to use the MSBuild engine for the specified item.</summary>
+ internal bool CheckUseMSBuildEngine (ConfigurationSelector sel, bool checkReferences = true)
+ {
+ // if the item mandates MSBuild, always use it
+ if (RequireMSBuildEngine)
+ return true;
+ // if the user has set the option, use the setting
+ if (UseMSBuildEngine.HasValue)
+ return UseMSBuildEngine.Value;
+
+ // If the item type defaults to using MSBuild, only use MSBuild if its direct references also use MSBuild.
+ // This prevents a not-uncommon common error referencing non-MSBuild projects from MSBuild projects
+ // NOTE: This adds about 11ms to the load/build/etc times of the MonoDevelop solution. Doing it recursively
+ // adds well over a second.
+ return UseMSBuildEngineByDefault && (
+ !checkReferences || GetReferencedItems (sel).OfType<Project>().All (i => i.CheckUseMSBuildEngine (sel, false))
+ );
+ }
+
/// <summary>
/// Adds a file to the project
/// </summary>
@@ -394,11 +873,15 @@ namespace MonoDevelop.Projects
//so in order to avoid doing them twice when using the msbuild engine, we special-case them
bool UsingMSBuildEngine (ConfigurationSelector sel)
{
- var msbuildHandler = ItemHandler as MonoDevelop.Projects.Formats.MSBuild.MSBuildProjectHandler;
- return msbuildHandler != null && msbuildHandler.UseMSBuildEngineForItem (this, sel);
+ return CheckUseMSBuildEngine (sel);
}
- protected override BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected override Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return RunTarget (monitor, "Build", configuration);
+ }
+
+ async Task<BuildResult> RunBuildTarget (ProgressMonitor monitor, ConfigurationSelector configuration)
{
// create output directory, if not exists
ProjectConfiguration conf = GetConfiguration (configuration) as ProjectConfiguration;
@@ -411,7 +894,7 @@ namespace MonoDevelop.Projects
StringParserService.Properties["Project"] = Name;
if (UsingMSBuildEngine (configuration)) {
- return DoBuild (monitor, configuration);
+ return await DoBuild (monitor, configuration);
}
string outputDir = conf.OutputDirectory;
@@ -429,7 +912,7 @@ namespace MonoDevelop.Projects
monitor.Log.WriteLine ("Performing main compilation...");
- BuildResult res = DoBuild (monitor, configuration);
+ BuildResult res = await DoBuild (monitor, configuration);
if (res != null) {
string errorString = GettextCatalog.GetPluralString ("{0} error", "{0} errors", res.ErrorCount, res.ErrorCount);
@@ -454,7 +937,7 @@ namespace MonoDevelop.Projects
/// Copies all support files to the output directory of the given configuration. Support files
/// include: assembly references with the Local Copy flag, data files with the Copy to Output option, etc.
/// </remarks>
- public void CopySupportFiles (IProgressMonitor monitor, ConfigurationSelector configuration)
+ public void CopySupportFiles (ProgressMonitor monitor, ConfigurationSelector configuration)
{
ProjectConfiguration config = (ProjectConfiguration) GetConfiguration (configuration);
@@ -505,7 +988,7 @@ namespace MonoDevelop.Projects
/// Deletes all support files from the output directory of the given configuration. Support files
/// include: assembly references with the Local Copy flag, data files with the Copy to Output option, etc.
/// </remarks>
- public void DeleteSupportFiles (IProgressMonitor monitor, ConfigurationSelector configuration)
+ public async Task DeleteSupportFiles (ProgressMonitor monitor, ConfigurationSelector configuration)
{
ProjectConfiguration config = (ProjectConfiguration) GetConfiguration (configuration);
@@ -517,7 +1000,7 @@ namespace MonoDevelop.Projects
continue;
try {
- dest.Delete ();
+ await dest.DeleteAsync ();
} catch (IOException ex) {
monitor.ReportError (GettextCatalog.GetString ("Error deleting support file '{0}'.", dest), ex);
}
@@ -559,13 +1042,17 @@ namespace MonoDevelop.Projects
/// </remarks>
internal protected virtual void PopulateSupportFileList (FileCopySet list, ConfigurationSelector configuration)
{
+ ProjectExtension.OnPopulateSupportFileList (list, configuration);
+ }
+ void DoPopulateSupportFileList (FileCopySet list, ConfigurationSelector configuration)
+ {
foreach (ProjectFile pf in Files) {
if (pf.CopyToOutputDirectory == FileCopyMode.None)
continue;
list.Add (pf.FilePath, pf.CopyToOutputDirectory == FileCopyMode.PreserveNewest, pf.ProjectVirtualPath);
}
}
-
+
/// <summary>
/// Gets a list of files generated when building this project
/// </summary>
@@ -601,6 +1088,10 @@ namespace MonoDevelop.Projects
/// </remarks>
internal protected virtual void PopulateOutputFileList (List<FilePath> list, ConfigurationSelector configuration)
{
+ ProjectExtension.OnPopulateOutputFileList (list, configuration);
+ }
+ void DoPopulateOutputFileList (List<FilePath> list, ConfigurationSelector configuration)
+ {
string file = GetOutputFileName (configuration);
if (file != null)
list.Add (file);
@@ -622,55 +1113,64 @@ namespace MonoDevelop.Projects
/// This method is invoked to build the project. Support files such as files with the Copy to Output flag will
/// be copied before calling this method.
/// </remarks>
- protected virtual BuildResult DoBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected async virtual Task<BuildResult> DoBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
{
- BuildResult res = ItemHandler.RunTarget (monitor, "Build", configuration);
+ BuildResult res = await RunMSBuildTarget (monitor, "Build", configuration);
return res ?? new BuildResult ();
}
- protected override void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected override Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return RunTarget (monitor, "Clean", configuration);
+ }
+
+ async Task<BuildResult> RunCleanTarget (ProgressMonitor monitor, ConfigurationSelector configuration)
{
ProjectConfiguration config = GetConfiguration (configuration) as ProjectConfiguration;
if (config == null) {
monitor.ReportError (GettextCatalog.GetString ("Configuration '{0}' not found in project '{1}'", configuration, Name), null);
- return;
+ return BuildResult.Success;
}
if (UsingMSBuildEngine (configuration)) {
- DoClean (monitor, config.Selector);
- return;
+ return await DoClean (monitor, config.Selector);
}
monitor.Log.WriteLine ("Removing output files...");
-
- // Delete generated files
- foreach (FilePath file in GetOutputFiles (configuration)) {
- if (File.Exists (file)) {
- file.Delete ();
- if (file.ParentDirectory.CanonicalPath != config.OutputDirectory.CanonicalPath && Directory.GetFiles (file.ParentDirectory).Length == 0)
- file.ParentDirectory.Delete ();
+
+ var filesToDelete = GetOutputFiles (configuration).ToArray ();
+
+ await Task.Factory.StartNew (delegate {
+ // Delete generated files
+ foreach (FilePath file in filesToDelete) {
+ if (File.Exists (file)) {
+ file.Delete ();
+ if (file.ParentDirectory.CanonicalPath != config.OutputDirectory.CanonicalPath && Directory.GetFiles (file.ParentDirectory).Length == 0)
+ file.ParentDirectory.Delete ();
+ }
}
- }
+ });
- DeleteSupportFiles (monitor, configuration);
+ await DeleteSupportFiles (monitor, configuration);
- DoClean (monitor, config.Selector);
+ var res = await DoClean (monitor, config.Selector);
monitor.Log.WriteLine (GettextCatalog.GetString ("Clean complete"));
+ return res;
}
- protected virtual void DoClean (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected virtual Task<BuildResult> DoClean (ProgressMonitor monitor, ConfigurationSelector configuration)
{
- ItemHandler.RunTarget (monitor, "Clean", configuration);
+ return RunMSBuildTarget (monitor, "Clean", configuration);
}
- protected internal override void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ protected async override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
ProjectConfiguration config = GetConfiguration (configuration) as ProjectConfiguration;
if (config == null) {
monitor.ReportError (GettextCatalog.GetString ("Configuration '{0}' not found in project '{1}'", configuration, Name), null);
return;
}
- DoExecute (monitor, context, configuration);
+ await DoExecute (monitor, context, configuration);
}
/// <summary>
@@ -685,8 +1185,9 @@ namespace MonoDevelop.Projects
/// <param name='configuration'>
/// Configuration to execute.
/// </param>
- protected virtual void DoExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ protected virtual Task DoExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
+ return new Task (delegate {});
}
/// <summary>
@@ -700,14 +1201,21 @@ namespace MonoDevelop.Projects
/// </param>
public virtual FilePath GetOutputFileName (ConfigurationSelector configuration)
{
- return FilePath.Null;
+ return ProjectExtension.OnGetOutputFileName (configuration);
}
- protected internal override bool OnGetNeedsBuilding (ConfigurationSelector configuration)
+ internal protected override bool OnGetNeedsBuilding (ConfigurationSelector configuration)
{
return CheckNeedsBuild (configuration);
}
+ protected override void OnSetNeedsBuilding (ConfigurationSelector configuration)
+ {
+ var of = GetOutputFileName (configuration);
+ if (File.Exists (of))
+ File.Delete (of);
+ }
+
/// <summary>
/// Checks if the project needs to be built
/// </summary>
@@ -734,7 +1242,7 @@ namespace MonoDevelop.Projects
}
}
- foreach (SolutionItem pref in GetReferencedItems (configuration)) {
+ foreach (SolutionFolderItem pref in GetReferencedItems (configuration)) {
if (pref.GetLastBuildTime (configuration) > tim)
return true;
}
@@ -778,16 +1286,19 @@ namespace MonoDevelop.Projects
}
}
- protected internal override List<FilePath> OnGetItemFiles (bool includeReferencedFiles)
+ protected override IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
{
- List<FilePath> col = base.OnGetItemFiles (includeReferencedFiles);
+ var baseFiles = base.OnGetItemFiles (includeReferencedFiles);
+
if (includeReferencedFiles) {
+ List<FilePath> col = new List<FilePath> ();
foreach (ProjectFile pf in Files) {
if (pf.Subtype != Subtype.Directory)
col.Add (pf.FilePath);
}
+ baseFiles = baseFiles.Concat (col);
}
- return col;
+ return baseFiles;
}
protected internal override void OnItemsAdded (IEnumerable<ProjectItem> objs)
@@ -908,6 +1419,775 @@ namespace MonoDevelop.Projects
}
}
+ internal void ReadProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ OnReadProjectHeader (monitor, msproject);
+ ProjectExtension.OnReadProject (monitor, msproject);
+ NeedsReload = false;
+ }
+
+ bool newProject;
+
+ internal MSBuildProject WriteProject (ProgressMonitor monitor)
+ {
+ MSBuildProject msproject = new MSBuildProject ();
+ newProject = FileName == null || !File.Exists (FileName);
+ if (newProject) {
+ if (SupportsBuild ())
+ msproject.DefaultTargets = "Build";
+ msproject.FileName = FileName;
+ } else {
+ msproject.Load (FileName);
+ }
+
+ OnWriteProjectHeader (monitor, msproject);
+ ProjectExtension.OnWriteProject (monitor, msproject);
+
+ return msproject;
+ }
+
+ class ConfigData
+ {
+ public ConfigData (string conf, string plt, IMSBuildPropertySet grp)
+ {
+ Config = conf;
+ Platform = plt;
+ Group = grp;
+ }
+
+ public bool FullySpecified {
+ get { return Config != Unspecified && Platform != Unspecified; }
+ }
+
+ public string Config;
+ public string Platform;
+ public IMSBuildPropertySet Group;
+ public bool Exists;
+ public bool IsNew; // The group did not exist in the original file
+ }
+
+ const string Unspecified = null;
+ ITimeTracker timer;
+
+ protected virtual void OnReadProjectHeader (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ timer = Counters.ReadMSBuildProject.BeginTiming ();
+
+ ToolsVersion = msproject.ToolsVersion;
+ if (string.IsNullOrEmpty (ToolsVersion))
+ ToolsVersion = "2.0";
+
+ IMSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup ();
+ // Avoid crash if there is not global group
+ if (globalGroup == null)
+ globalGroup = msproject.AddNewPropertyGroup (false);
+
+ productVersion = globalGroup.GetValue ("ProductVersion");
+ schemaVersion = globalGroup.GetValue ("SchemaVersion");
+
+ // Get the project ID
+
+ string itemGuid = globalGroup.GetValue ("ProjectGuid");
+ if (itemGuid == null)
+ throw new UserException ("Project file doesn't have a valid ProjectGuid");
+
+ // Workaround for a VS issue. VS doesn't include the curly braces in the ProjectGuid
+ // of shared projects.
+ if (!itemGuid.StartsWith ("{", StringComparison.Ordinal))
+ itemGuid = "{" + itemGuid + "}";
+
+ ItemId = itemGuid.ToUpper ();
+
+ // Get the project GUIDs
+
+ string projectTypeGuids = globalGroup.GetValue ("ProjectTypeGuids");
+
+ var subtypeGuids = new List<string> ();
+ if (projectTypeGuids != null) {
+ foreach (string guid in projectTypeGuids.Split (';')) {
+ string sguid = guid.Trim ();
+ if (sguid.Length > 0 && string.Compare (sguid, TypeGuid, StringComparison.OrdinalIgnoreCase) != 0)
+ subtypeGuids.Add (guid);
+ }
+ }
+ flavorGuids = subtypeGuids.ToArray ();
+
+ if (!CheckAllFlavorsSupported ()) {
+ var guids = new [] { TypeGuid };
+ var projectInfo = MSBuildProjectService.GetUnknownProjectTypeInfo (guids.Concat (flavorGuids).ToArray (), FileName);
+ IsUnsupportedProject = true;
+ if (projectInfo != null)
+ UnsupportedProjectMessage = projectInfo.GetInstructions ();
+ }
+
+ // Common properties
+
+ Description = msproject.EvaluatedProperties.GetValue ("Description", "");
+ baseIntermediateOutputPath = msproject.EvaluatedProperties.GetPathValue ("BaseIntermediateOutputPath", defaultValue:BaseDirectory.Combine ("obj"), relativeToProject:true);
+
+ RemoveDuplicateItems (msproject);
+ }
+
+ protected virtual void OnReadProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ timer.Trace ("Read project items");
+ LoadProjectItems (msproject, ProjectItemFlags.None);
+
+ timer.Trace ("Read configurations");
+
+ List<ConfigData> configData = GetConfigData (msproject, false);
+ List<ConfigData> partialConfigurations = new List<ConfigData> ();
+ HashSet<string> handledConfigurations = new HashSet<string> ();
+ var configurations = new HashSet<string> ();
+ var platforms = new HashSet<string> ();
+
+ IMSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup ();
+ configData.Insert (0, new ConfigData (Unspecified, Unspecified, globalGroup));
+
+ // Load configurations, skipping the dummy config at index 0.
+ for (int i = 1; i < configData.Count; i++) {
+ ConfigData cgrp = configData[i];
+ string platform = cgrp.Platform;
+ string conf = cgrp.Config;
+
+ if (platform != Unspecified)
+ platforms.Add (platform);
+
+ if (conf != Unspecified)
+ configurations.Add (conf);
+
+ if (conf == Unspecified || platform == Unspecified) {
+ // skip partial configurations for now...
+ partialConfigurations.Add (cgrp);
+ continue;
+ }
+
+ string key = conf + "|" + platform;
+ if (handledConfigurations.Contains (key))
+ continue;
+
+ LoadConfiguration (monitor, configData, conf, platform);
+
+ handledConfigurations.Add (key);
+ }
+
+ // Now we can load any partial configurations by combining them with known configs or platforms.
+ if (partialConfigurations.Count > 0) {
+ if (platforms.Count == 0)
+ platforms.Add (string.Empty); // AnyCpu
+
+ foreach (ConfigData cgrp in partialConfigurations) {
+ if (cgrp.Config != Unspecified && cgrp.Platform == Unspecified) {
+ string conf = cgrp.Config;
+
+ foreach (var platform in platforms) {
+ string key = conf + "|" + platform;
+
+ if (handledConfigurations.Contains (key))
+ continue;
+
+ LoadConfiguration (monitor, configData, conf, platform);
+
+ handledConfigurations.Add (key);
+ }
+ } else if (cgrp.Config == Unspecified && cgrp.Platform != Unspecified) {
+ string platform = cgrp.Platform;
+
+ foreach (var conf in configurations) {
+ string key = conf + "|" + platform;
+
+ if (handledConfigurations.Contains (key))
+ continue;
+
+ LoadConfiguration (monitor, configData, conf, platform);
+
+ handledConfigurations.Add (key);
+ }
+ }
+ }
+ }
+
+ // Read extended properties
+
+ timer.Trace ("Read extended properties");
+ }
+
+ List<ConfigData> GetConfigData (MSBuildProject msproject, bool includeGlobalGroups)
+ {
+ List<ConfigData> configData = new List<ConfigData> ();
+ foreach (MSBuildPropertyGroup cgrp in msproject.PropertyGroups) {
+ string conf, platform;
+ if (ParseConfigCondition (cgrp.Condition, out conf, out platform) || includeGlobalGroups)
+ configData.Add (new ConfigData (conf, platform, cgrp));
+ }
+ return configData;
+ }
+
+ bool ParseConfigCondition (string cond, out string config, out string platform)
+ {
+ config = platform = Unspecified;
+ int i = cond.IndexOf ("==", StringComparison.Ordinal);
+ if (i == -1)
+ return false;
+ if (cond.Substring (0, i).Trim () == "'$(Configuration)|$(Platform)'") {
+ if (!ExtractConfigName (cond.Substring (i + 2), out cond))
+ return false;
+ i = cond.IndexOf ('|');
+ if (i != -1) {
+ config = cond.Substring (0, i);
+ platform = cond.Substring (i+1);
+ } else {
+ // Invalid configuration
+ return false;
+ }
+ if (platform == "AnyCPU")
+ platform = string.Empty;
+ return true;
+ }
+ else if (cond.Substring (0, i).Trim () == "'$(Configuration)'") {
+ if (!ExtractConfigName (cond.Substring (i + 2), out config))
+ return false;
+ platform = Unspecified;
+ return true;
+ }
+ else if (cond.Substring (0, i).Trim () == "'$(Platform)'") {
+ config = Unspecified;
+ if (!ExtractConfigName (cond.Substring (i + 2), out platform))
+ return false;
+ if (platform == "AnyCPU")
+ platform = string.Empty;
+ return true;
+ }
+ return false;
+ }
+
+ bool ExtractConfigName (string name, out string config)
+ {
+ config = name.Trim (' ');
+ if (config.Length <= 2)
+ return false;
+ if (config [0] != '\'' || config [config.Length - 1] != '\'')
+ return false;
+ config = config.Substring (1, config.Length - 2);
+ return config.IndexOf ('\'') == -1;
+ }
+
+ void LoadConfiguration (ProgressMonitor monitor, List<ConfigData> configData, string conf, string platform)
+ {
+ IMSBuildPropertySet grp = GetMergedConfiguration (configData, conf, platform, null);
+ ProjectConfiguration config = (ProjectConfiguration) CreateConfiguration (conf);
+
+ config.Platform = platform;
+ projectExtension.OnReadConfiguration (monitor, config, grp);
+ Configurations.Add (config);
+ }
+
+ protected virtual void OnReadConfiguration (ProgressMonitor monitor, ProjectConfiguration config, IMSBuildPropertySet grp)
+ {
+ config.Read (grp, GetToolsFormat ());
+ }
+
+ void RemoveDuplicateItems (MSBuildProject msproject)
+ {
+ timer.Trace ("Checking for duplicate items");
+
+ var uniqueIncludes = new Dictionary<string,object> ();
+ var toRemove = new List<MSBuildItem> ();
+ foreach (MSBuildItem bi in msproject.GetAllItems ()) {
+ object existing;
+ string key = bi.Name + "<" + bi.Include;
+ if (!uniqueIncludes.TryGetValue (key, out existing)) {
+ uniqueIncludes[key] = bi;
+ continue;
+ }
+ var exBi = existing as MSBuildItem;
+ if (exBi != null) {
+ if (exBi.Condition != bi.Condition || exBi.Element.InnerXml != bi.Element.InnerXml) {
+ uniqueIncludes[key] = new List<MSBuildItem> { exBi, bi };
+ } else {
+ toRemove.Add (bi);
+ }
+ continue;
+ }
+
+ var exList = (List<MSBuildItem>)existing;
+ bool found = false;
+ foreach (var m in (exList)) {
+ if (m.Condition == bi.Condition && m.Element.InnerXml == bi.Element.InnerXml) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ exList.Add (bi);
+ } else {
+ toRemove.Add (bi);
+ }
+ }
+ if (toRemove.Count == 0)
+ return;
+
+ timer.Trace ("Removing duplicate items");
+
+ foreach (var t in toRemove)
+ msproject.RemoveItem (t);
+ }
+
+ IMSBuildPropertySet GetMergedConfiguration (List<ConfigData> configData, string conf, string platform, IMSBuildPropertySet propGroupLimit)
+ {
+ IMSBuildPropertySet merged = null;
+
+ foreach (ConfigData grp in configData) {
+ if (grp.Group == propGroupLimit)
+ break;
+ if ((grp.Config == conf || grp.Config == Unspecified || conf == Unspecified) && (grp.Platform == platform || grp.Platform == Unspecified || platform == Unspecified)) {
+ if (merged == null)
+ merged = grp.Group;
+ else if (merged is MSBuildPropertyGroupMerged)
+ ((MSBuildPropertyGroupMerged)merged).Add (grp.Group);
+ else {
+ MSBuildPropertyGroupMerged m = new MSBuildPropertyGroupMerged (merged.Project, GetToolsFormat());
+ m.Add (merged);
+ m.Add (grp.Group);
+ merged = m;
+ }
+ }
+ }
+ return merged;
+ }
+
+ //HACK: the solution's format is irrelevant to MSBuild projects, what matters is the ToolsVersion
+ // but other parts of the MD API expect a FileFormat
+ internal MSBuildFileFormat GetToolsFormat ()
+ {
+ switch (ToolsVersion) {
+ case "2.0":
+ return new MSBuildFileFormatVS05 ();
+ case "3.5":
+ return new MSBuildFileFormatVS08 ();
+ case "4.0":
+ if (SolutionFormat != null && SolutionFormat.Id == "MSBuild10")
+ return SolutionFormat;
+ return new MSBuildFileFormatVS12 ();
+ case "12.0":
+ return new MSBuildFileFormatVS12 ();
+ default:
+ throw new Exception ("Unknown ToolsVersion '" + ToolsVersion + "'");
+ }
+ }
+
+ internal void LoadProjectItems (MSBuildProject msproject, ProjectItemFlags flags)
+ {
+ foreach (var buildItem in msproject.GetAllItems ()) {
+ ProjectItem it = ReadItem (buildItem);
+ if (it == null)
+ continue;
+ it.Flags = flags;
+ if (it is ProjectFile) {
+ var file = (ProjectFile)it;
+ if (file.Name.IndexOf ('*') > -1) {
+ // Thanks to IsOriginatedFromWildcard, these expanded items will not be saved back to disk.
+ foreach (var expandedItem in ResolveWildcardItems (file))
+ Items.Add (expandedItem);
+ // Add to wildcard items (so it can be re-saved) instead of Items (where tools will
+ // try to compile and display these nonstandard items
+ WildcardItems.Add (it);
+ continue;
+ }
+ }
+ Items.Add (it);
+ }
+ }
+
+ internal override void SetSolutionFormat (MSBuildFileFormat format, bool converting)
+ {
+ base.SetSolutionFormat (format, converting);
+
+ // when converting formats, set ToolsVersion, ProductVersion, SchemaVersion to default values written by VS
+ // this happens on creation too
+ // else we leave them alone and just roundtrip them
+ if (converting) {
+ ToolsVersion = format.DefaultToolsVersion;
+ productVersion = format.DefaultProductVersion;
+ schemaVersion = format.DefaultSchemaVersion;
+ }
+ }
+
+ internal ProjectItem ReadItem (IMSBuildItemEvaluated buildItem)
+ {
+ var item = CreateProjectItem (buildItem);
+ item.Read (this, buildItem);
+ return item;
+ }
+
+ const string RecursiveDirectoryWildcard = "**";
+ static readonly char[] directorySeparators = new [] {
+ Path.DirectorySeparatorChar,
+ Path.AltDirectorySeparatorChar
+ };
+
+ static string GetWildcardDirectoryName (string path)
+ {
+ int indexOfLast = path.LastIndexOfAny (directorySeparators);
+ if (indexOfLast < 0)
+ return String.Empty;
+ return path.Substring (0, indexOfLast);
+ }
+
+ static string GetWildcardFileName (string path)
+ {
+ int indexOfLast = path.LastIndexOfAny (directorySeparators);
+ if (indexOfLast < 0)
+ return path;
+ if (indexOfLast == path.Length)
+ return String.Empty;
+ return path.Substring (indexOfLast + 1, path.Length - (indexOfLast + 1));
+ }
+
+
+ static IEnumerable<string> ExpandWildcardFilePath (string filePath)
+ {
+ if (String.IsNullOrWhiteSpace (filePath))
+ throw new ArgumentException ("Not a wildcard path");
+
+ string dir = GetWildcardDirectoryName (filePath);
+ string file = GetWildcardFileName (filePath);
+
+ if (String.IsNullOrEmpty (dir) || String.IsNullOrEmpty (file))
+ return null;
+
+ SearchOption searchOption = SearchOption.TopDirectoryOnly;
+ if (dir.EndsWith (RecursiveDirectoryWildcard, StringComparison.Ordinal)) {
+ dir = dir.Substring (0, dir.Length - RecursiveDirectoryWildcard.Length);
+ searchOption = SearchOption.AllDirectories;
+ }
+
+ if (!Directory.Exists (dir))
+ return null;
+
+ return Directory.GetFiles (dir, file, searchOption);
+ }
+
+ static IEnumerable<ProjectFile> ResolveWildcardItems (ProjectFile wildcardFile)
+ {
+ var paths = ExpandWildcardFilePath (wildcardFile.Name);
+ if (paths == null)
+ yield break;
+ foreach (var resolvedFilePath in paths) {
+ var projectFile = (ProjectFile)wildcardFile.Clone ();
+ projectFile.Name = resolvedFilePath;
+ projectFile.Flags |= ProjectItemFlags.DontPersist;
+ yield return projectFile;
+ }
+ }
+
+ struct MergedPropertyValue
+ {
+ public readonly string XmlValue;
+ public readonly bool PreserveExistingCase;
+ public readonly bool IsDefault;
+
+ public MergedPropertyValue (string xmlValue, bool preserveExistingCase, bool isDefault)
+ {
+ this.XmlValue = xmlValue;
+ this.PreserveExistingCase = preserveExistingCase;
+ this.IsDefault = isDefault;
+ }
+ }
+
+ protected virtual void OnWriteProjectHeader (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ IMSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup ();
+ if (globalGroup == null)
+ globalGroup = msproject.AddNewPropertyGroup (false);
+
+ if (Configurations.Count > 0) {
+ ItemConfiguration conf = Configurations.FirstOrDefault<ItemConfiguration> (c => c.Name == "Debug");
+ if (conf == null) conf = Configurations [0];
+ globalGroup.SetValue ("Configuration", conf.Name, condition:" '$(Configuration)' == '' ");
+
+ string platform = conf.Platform.Length == 0 ? "AnyCPU" : conf.Platform;
+ globalGroup.SetValue ("Platform", platform, condition:" '$(Platform)' == '' ");
+ }
+
+ if (TypeGuid == MSBuildProjectService.GenericItemGuid) {
+ DataType dt = MSBuildProjectService.DataContext.GetConfigurationDataType (GetType ());
+ globalGroup.SetValue ("ItemType", dt.Name);
+ }
+
+ globalGroup.SetValue ("ProductVersion", productVersion);
+ globalGroup.SetValue ("SchemaVersion", schemaVersion);
+
+ globalGroup.SetValue ("ProjectGuid", ItemId);
+
+ if (flavorGuids.Length > 0) {
+ string gg = string.Join (";", flavorGuids);
+ gg += ";" + TypeGuid;
+ globalGroup.SetValue ("ProjectTypeGuids", gg.ToUpper (), preserveExistingCase:true);
+ } else {
+ globalGroup.RemoveProperty ("ProjectTypeGuids");
+ }
+
+ // having no ToolsVersion is equivalent to 2.0, roundtrip that correctly
+ if (ToolsVersion != "2.0")
+ msproject.ToolsVersion = ToolsVersion;
+ else if (string.IsNullOrEmpty (msproject.ToolsVersion))
+ msproject.ToolsVersion = null;
+ else
+ msproject.ToolsVersion = "2.0";
+
+ msproject.GetGlobalPropertyGroup ().SetValue ("Description", Description, "");
+ msproject.GetGlobalPropertyGroup ().SetValue ("BaseIntermediateOutputPath", BaseIntermediateOutputPath, defaultValue:BaseDirectory.Combine ("obj"), relativeToProject:true);
+ }
+
+ protected virtual void OnWriteProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ var toolsFormat = GetToolsFormat ();
+
+ IMSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup ();
+
+ // Configurations
+
+ if (Configurations.Count > 0) {
+ List<ConfigData> configData = GetConfigData (msproject, true);
+
+ // Write configuration data, creating new property groups if necessary
+
+ foreach (ProjectConfiguration conf in Configurations) {
+ ConfigData cdata = FindPropertyGroup (configData, conf);
+ if (cdata == null) {
+ MSBuildPropertyGroup pg = msproject.AddNewPropertyGroup (true);
+ pg.IgnoreDefaultValues = true;
+ pg.Condition = BuildConfigCondition (conf.Name, conf.Platform);
+ cdata = new ConfigData (conf.Name, conf.Platform, pg);
+ cdata.IsNew = true;
+ configData.Add (cdata);
+ }
+ ((MSBuildPropertyGroup)cdata.Group).IgnoreDefaultValues = true;
+ cdata.Exists = true;
+ ProjectExtension.OnWriteConfiguration (monitor, conf, cdata.Group);
+ }
+
+ // Find the properties in all configurations that have the MergeToProject flag set
+ var mergeToProjectProperties = new HashSet<MergedProperty> (GetMergeToProjectProperties (configData));
+ var mergeToProjectPropertyNames = new HashSet<string> (mergeToProjectProperties.Select (p => p.Name));
+ var mergeToProjectPropertyValues = new Dictionary<string,MergedPropertyValue> ();
+
+ foreach (ProjectConfiguration conf in Configurations) {
+ ConfigData cdata = FindPropertyGroup (configData, conf);
+ var propGroup = (MSBuildPropertyGroup) cdata.Group;
+
+ IMSBuildPropertySet baseGroup = GetMergedConfiguration (configData, conf.Name, conf.Platform, propGroup);
+
+ CollectMergetoprojectProperties (propGroup, mergeToProjectProperties, mergeToProjectPropertyValues);
+
+ propGroup.UnMerge (baseGroup, mergeToProjectPropertyNames);
+ propGroup.IgnoreDefaultValues = false;
+ }
+
+ // Move properties with common values from configurations to the main
+ // property group
+ foreach (KeyValuePair<string,MergedPropertyValue> prop in mergeToProjectPropertyValues) {
+ if (!prop.Value.IsDefault)
+ globalGroup.SetValue (prop.Key, prop.Value.XmlValue, preserveExistingCase: prop.Value.PreserveExistingCase);
+ else
+ globalGroup.RemoveProperty (prop.Key);
+ }
+ foreach (string prop in mergeToProjectPropertyNames) {
+ if (!mergeToProjectPropertyValues.ContainsKey (prop))
+ globalGroup.RemoveProperty (prop);
+ }
+ foreach (SolutionItemConfiguration conf in Configurations) {
+ var propGroup = FindPropertyGroup (configData, conf).Group;
+ foreach (string mp in mergeToProjectPropertyValues.Keys)
+ propGroup.RemoveProperty (mp);
+ }
+
+ // Remove groups corresponding to configurations that have been removed
+ // or groups which don't have any property and did not already exist
+ foreach (ConfigData cd in configData) {
+ if ((!cd.Exists && cd.FullySpecified) || (cd.IsNew && !cd.Group.Properties.Any ()))
+ msproject.RemoveGroup ((MSBuildPropertyGroup)cd.Group);
+ }
+ }
+ SaveProjectItems (monitor, toolsFormat, msproject);
+
+ if (msproject.IsNewProject) {
+ foreach (var im in DefaultImports)
+ msproject.AddNewImport (im);
+ }
+
+ foreach (var im in importsAdded) {
+ if (msproject.GetImport (im.Name, im.Condition) == null)
+ msproject.AddNewImport (im.Name, im.Condition);
+ }
+ foreach (var im in importsRemoved) {
+ var i = msproject.GetImport (im.Name, im.Condition);
+ if (i != null)
+ msproject.RemoveImport (i);
+ }
+ }
+
+ void WriteConfiguration (ProgressMonitor monitor, List<ConfigData> configData, string conf, string platform)
+ {
+ IMSBuildPropertySet grp = GetMergedConfiguration (configData, conf, platform, null);
+ ProjectConfiguration config = (ProjectConfiguration) CreateConfiguration (conf);
+
+ config.Platform = platform;
+ config.Read (grp, GetToolsFormat ());
+ Configurations.Add (config);
+ projectExtension.OnReadConfiguration (monitor, config, grp);
+ }
+
+ protected virtual void OnWriteConfiguration (ProgressMonitor monitor, ProjectConfiguration config, IMSBuildPropertySet pset)
+ {
+ config.Write (pset, SolutionFormat);
+ }
+
+ IEnumerable<MergedProperty> GetMergeToProjectProperties (List<ConfigData> configData)
+ {
+ Dictionary<string,MergedProperty> mergeProps = new Dictionary<string, MergedProperty> ();
+ foreach (var cd in configData.Where (d => d.FullySpecified)) {
+ foreach (var prop in cd.Group.Properties) {
+ if (!prop.MergeToMainGroup) {
+ mergeProps [prop.Name] = null;
+ } else if (!mergeProps.ContainsKey (prop.Name))
+ mergeProps [prop.Name] = prop.CreateMergedProperty ();
+ }
+ }
+ return mergeProps.Values.Where (p => p != null);
+ }
+
+ void CollectMergetoprojectProperties (IMSBuildPropertySet pgroup, HashSet<MergedProperty> properties, Dictionary<string,MergedPropertyValue> mergeToProjectProperties)
+ {
+ // This method checks every property in pgroup which has the MergeToProject flag.
+ // If the value of this property is the same as the one stored in mergeToProjectProperties
+ // it means that the property can be merged to the main project property group (so far).
+
+ foreach (var pinfo in new List<MergedProperty> (properties)) {
+ MSBuildProperty prop = pgroup.GetProperty (pinfo.Name);
+
+ MergedPropertyValue mvalue;
+ if (!mergeToProjectProperties.TryGetValue (pinfo.Name, out mvalue)) {
+ if (prop != null) {
+ // This is the first time the value is checked. Just assign it.
+ mergeToProjectProperties.Add (pinfo.Name, new MergedPropertyValue (prop.Value, pinfo.PreserveExistingCase, pinfo.IsDefault));
+ continue;
+ }
+ // If there is no value, it can't be merged
+ }
+ else if (prop != null && string.Equals (prop.Value, mvalue.XmlValue, mvalue.PreserveExistingCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
+ // Same value. It can be merged.
+ continue;
+
+ // The property can't be merged because different configurations have different
+ // values for it. Remove it from the list.
+ properties.Remove (pinfo);
+ mergeToProjectProperties.Remove (pinfo.Name);
+ }
+ }
+
+ struct ItemInfo {
+ public MSBuildItem Item;
+ public bool Added;
+ }
+
+ internal void SaveProjectItems (ProgressMonitor monitor, MSBuildFileFormat toolsFormat, MSBuildProject msproject, string pathPrefix = null)
+ {
+ // Remove old items
+ Dictionary<string, ItemInfo> oldItems = new Dictionary<string, ItemInfo> ();
+ foreach (MSBuildItem item in msproject.GetAllItems ())
+ oldItems [item.Name + "<" + item.UnevaluatedInclude + "<" + item.Condition] = new ItemInfo () {
+ Item = item
+ };
+ // Add the new items
+ foreach (ProjectItem ob in Items.Concat (WildcardItems).Where (it => !it.Flags.HasFlag (ProjectItemFlags.DontPersist)))
+ SaveProjectItem (monitor, toolsFormat, msproject, ob, oldItems, pathPrefix);
+ foreach (ItemInfo itemInfo in oldItems.Values) {
+ if (!itemInfo.Added)
+ msproject.RemoveItem (itemInfo.Item);
+ }
+ }
+
+ void SaveProjectItem (ProgressMonitor monitor, MSBuildFileFormat fmt, MSBuildProject msproject, ProjectItem item, Dictionary<string,ItemInfo> oldItems, string pathPrefix = null)
+ {
+ var include = item.UnevaluatedInclude ?? item.Include;
+ if (pathPrefix != null && !include.StartsWith (pathPrefix))
+ include = pathPrefix + include;
+
+ MSBuildItem buildItem = AddOrGetBuildItem (msproject, oldItems, item.ItemName, include, item.Condition);
+ item.Write (fmt, buildItem);
+ if (pathPrefix != null)
+ buildItem.Include = include;
+ }
+
+ MSBuildItem AddOrGetBuildItem (MSBuildProject msproject, Dictionary<string,ItemInfo> oldItems, string name, string include, string condition)
+ {
+ ItemInfo itemInfo;
+ string key = name + "<" + include + "<" + condition;
+ if (oldItems.TryGetValue (key, out itemInfo)) {
+ if (!itemInfo.Added) {
+ itemInfo.Added = true;
+ oldItems [key] = itemInfo;
+ }
+ return itemInfo.Item;
+ } else {
+ return msproject.AddNewItem (name, include);
+ }
+ }
+
+ ConfigData FindPropertyGroup (List<ConfigData> configData, SolutionItemConfiguration config)
+ {
+ foreach (ConfigData data in configData) {
+ if (data.Config == config.Name && data.Platform == config.Platform)
+ return data;
+ }
+ return null;
+ }
+
+ string BuildConfigCondition (string config, string platform)
+ {
+ if (platform.Length == 0)
+ platform = "AnyCPU";
+ return " '$(Configuration)|$(Platform)' == '" + config + "|" + platform + "' ";
+ }
+
+ bool IsMergeToProjectProperty (ItemProperty prop)
+ {
+ foreach (object at in prop.CustomAttributes) {
+ if (at is MergeToProjectAttribute)
+ return true;
+ }
+ return false;
+ }
+
+ public void AddImportIfMissing (string name, string condition)
+ {
+ importsAdded.Add (new DotNetProjectImport (name, condition));
+ }
+
+ public void RemoveImport (string name)
+ {
+ importsRemoved.Add (new DotNetProjectImport (name));
+ }
+
+ List <DotNetProjectImport> importsAdded = new List<DotNetProjectImport> ();
+
+ internal IList<DotNetProjectImport> ImportsAdded {
+ get { return importsAdded; }
+ }
+
+ List <DotNetProjectImport> importsRemoved = new List<DotNetProjectImport> ();
+
+ internal IList<DotNetProjectImport> ImportsRemoved {
+ get { return importsRemoved; }
+ }
+
+ void ImportsSaved ()
+ {
+ importsAdded.Clear ();
+ importsRemoved.Clear ();
+ }
internal void NotifyFileRenamedInProject (ProjectFileRenamedEventArgs args)
{
NotifyModified ("Files");
@@ -919,6 +2199,10 @@ namespace MonoDevelop.Projects
/// </summary>
protected virtual void OnFileRemovedFromProject (ProjectFileEventArgs e)
{
+ ProjectExtension.OnFileRemovedFromProject (e);
+ }
+ void DoOnFileRemovedFromProject (ProjectFileEventArgs e)
+ {
buildActions = null;
if (FileRemovedFromProject != null) {
FileRemovedFromProject (this, e);
@@ -930,38 +2214,54 @@ namespace MonoDevelop.Projects
/// </summary>
protected virtual void OnFileAddedToProject (ProjectFileEventArgs e)
{
+ ProjectExtension.OnFileAddedToProject (e);
+ }
+ void DoOnFileAddedToProject (ProjectFileEventArgs e)
+ {
buildActions = null;
if (FileAddedToProject != null) {
FileAddedToProject (this, e);
}
}
-
+
/// <summary>
/// Raises the FileChangedInProject event.
/// </summary>
protected virtual void OnFileChangedInProject (ProjectFileEventArgs e)
{
+ ProjectExtension.OnFileChangedInProject (e);
+ }
+ void DoOnFileChangedInProject (ProjectFileEventArgs e)
+ {
if (FileChangedInProject != null) {
FileChangedInProject (this, e);
}
}
-
+
/// <summary>
/// Raises the FilePropertyChangedInProject event.
/// </summary>
protected virtual void OnFilePropertyChangedInProject (ProjectFileEventArgs e)
{
+ ProjectExtension.OnFilePropertyChangedInProject (e);
+ }
+ void DoOnFilePropertyChangedInProject (ProjectFileEventArgs e)
+ {
buildActions = null;
if (FilePropertyChangedInProject != null) {
FilePropertyChangedInProject (this, e);
}
}
-
+
/// <summary>
/// Raises the FileRenamedInProject event.
/// </summary>
protected virtual void OnFileRenamedInProject (ProjectFileRenamedEventArgs e)
{
+ ProjectExtension.OnFileRenamedInProject (e);
+ }
+ void DoOnFileRenamedInProject (ProjectFileRenamedEventArgs e)
+ {
if (FileRenamedInProject != null) {
FileRenamedInProject (this, e);
}
@@ -991,6 +2291,126 @@ namespace MonoDevelop.Projects
/// Occurs when a file of this project has been renamed
/// </summary>
public event ProjectFileRenamedEventHandler FileRenamedInProject;
+
+
+ class DefaultMSBuildProjectExtension: ProjectExtension
+ {
+ internal protected override bool SupportsFlavor (string guid)
+ {
+ return false;
+ }
+
+ internal protected override bool OnGetIsCompileable (string fileName)
+ {
+ return false;
+ }
+
+ internal protected override void OnGetProjectTypes (HashSet<string> types)
+ {
+ Project.OnGetProjectTypes (types);
+ }
+
+ internal protected override Task<BuildResult> OnRunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ {
+ return Project.DoRunTarget (monitor, target, configuration);
+ }
+
+ internal protected override bool OnGetSupportsTarget (string target)
+ {
+ return Project.OnGetSupportsTarget (target);
+ }
+
+ internal protected override string OnGetDefaultBuildAction (string fileName)
+ {
+ return Project.IsCompileable (fileName) ? BuildAction.Compile : BuildAction.None;
+ }
+
+ internal protected override string OnGetDefaultResourceId (ProjectFile projectFile)
+ {
+ return Project.OnGetDefaultResourceId (projectFile);
+ }
+
+ internal protected override IEnumerable<string> OnGetStandardBuildActions ()
+ {
+ return BuildAction.StandardActions;
+ }
+
+ internal protected override IList<string> OnGetCommonBuildActions ()
+ {
+ return BuildAction.StandardActions;
+ }
+
+ internal protected override ProjectItem OnCreateProjectItem (IMSBuildItemEvaluated item)
+ {
+ return Project.OnCreateProjectItem (item);
+ }
+
+ internal protected override void OnPopulateSupportFileList (FileCopySet list, ConfigurationSelector configuration)
+ {
+ Project.DoPopulateSupportFileList (list, configuration);
+ }
+
+ internal protected override void OnPopulateOutputFileList (List<FilePath> list, ConfigurationSelector configuration)
+ {
+ Project.DoPopulateOutputFileList (list, configuration);
+ }
+
+ internal protected override FilePath OnGetOutputFileName (ConfigurationSelector configuration)
+ {
+ return FilePath.Null;
+ }
+
+ internal protected override string[] SupportedLanguages {
+ get {
+ return new String[] { "" };
+ }
+ }
+
+ internal protected override void OnFileRemovedFromProject (ProjectFileEventArgs e)
+ {
+ Project.DoOnFileRemovedFromProject (e);
+ }
+
+ internal protected override void OnFileAddedToProject (ProjectFileEventArgs e)
+ {
+ Project.DoOnFileAddedToProject (e);
+ }
+
+ internal protected override void OnFileChangedInProject (ProjectFileEventArgs e)
+ {
+ Project.DoOnFileChangedInProject (e);
+ }
+
+ internal protected override void OnFilePropertyChangedInProject (ProjectFileEventArgs e)
+ {
+ Project.DoOnFilePropertyChangedInProject (e);
+ }
+
+ internal protected override void OnFileRenamedInProject (ProjectFileRenamedEventArgs e)
+ {
+ Project.DoOnFileRenamedInProject (e);
+ }
+
+ internal protected override void OnReadProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ Project.OnReadProject (monitor, msproject);
+ }
+
+ internal protected override void OnWriteProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ Project.OnWriteProject (monitor, msproject);
+ }
+
+ internal protected override void OnReadConfiguration (ProgressMonitor monitor, ProjectConfiguration config, IMSBuildPropertySet grp)
+ {
+ Project.OnReadConfiguration (monitor, config, grp);
+ }
+
+ internal protected override void OnWriteConfiguration (ProgressMonitor monitor, ProjectConfiguration config, IMSBuildPropertySet grp)
+ {
+ Project.OnWriteConfiguration (monitor, config, grp);
+ }
+ }
}
public delegate void ProjectEventHandler (Object sender, ProjectEventArgs e);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConfiguration.cs
index 1db4404892..7a4420c57c 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConfiguration.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConfiguration.cs
@@ -32,10 +32,12 @@ using System.IO;
using MonoDevelop.Core.Serialization;
using System.Collections.Generic;
using MonoDevelop.Core.StringParsing;
+using System.Xml.Linq;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
- public class ProjectConfiguration : SolutionItemConfiguration
+ public class ProjectConfiguration : SolutionItemConfiguration, IMSBuildDataObject
{
public ProjectConfiguration ()
@@ -46,8 +48,64 @@ namespace MonoDevelop.Projects
{
}
- [ProjectPathItemProperty("IntermediateOutputPath")]
- private FilePath intermediateOutputDirectory;
+ #region IProjectConfigurationData implementation
+
+ void IMSBuildDataObject.Read (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ Read (pset, format);
+ }
+
+ void IMSBuildDataObject.Write (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ Write (pset, format);
+ }
+
+ #endregion
+
+ internal protected virtual void Read (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ intermediateOutputDirectory = pset.GetPathValue ("IntermediateOutputPath");
+ outputDirectory = pset.GetPathValue ("OutputPath", defaultValue:"." + Path.DirectorySeparatorChar);
+ debugMode = pset.GetValue<bool> ("DebugSymbols");
+ pauseConsoleOutput = pset.GetValue ("ConsolePause", true);
+ externalConsole = pset.GetValue<bool> ("ExternalConsole");
+ commandLineParameters = pset.GetValue ("Commandlineparameters", "");
+ runWithWarnings = pset.GetValue ("RunWithWarnings", true);
+
+ var svars = pset.GetValue ("EnvironmentVariables");
+ if (svars != null) {
+ XElement vars = XElement.Parse (svars);
+ foreach (var val in vars.Elements ("Variable")) {
+ var name = (string)val.Attribute ("name");
+ if (name != null)
+ environmentVariables [name] = (string)val.Attribute ("value");
+ }
+ }
+ }
+
+ internal protected virtual void Write (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ pset.SetValue ("IntermediateOutputPath", intermediateOutputDirectory, defaultValue:FilePath.Null);
+ pset.SetValue ("DebugSymbols", debugMode, false);
+ pset.SetValue ("OutputPath", outputDirectory);
+ pset.SetValue ("ConsolePause", pauseConsoleOutput, true);
+ pset.SetValue ("ExternalConsole", externalConsole, false);
+ pset.SetValue ("Commandlineparameters", commandLineParameters, "");
+ pset.SetValue ("RunWithWarnings", runWithWarnings, true);
+
+ if (environmentVariables.Count > 0) {
+ XElement e = new XElement ("EnvironmentVariables");
+ foreach (var v in environmentVariables) {
+ var val = new XElement ("Variable");
+ val.SetAttributeValue ("name", v.Key);
+ val.SetAttributeValue ("value", v.Value);
+ e.Add (val);
+ }
+ pset.SetValue ("EnvironmentVariables", e.ToString ());
+ }
+ }
+
+ FilePath intermediateOutputDirectory = FilePath.Empty;
public virtual FilePath IntermediateOutputDirectory {
get {
@@ -66,46 +124,37 @@ namespace MonoDevelop.Projects
}
}
- [ProjectPathItemProperty("OutputPath")]
- private FilePath outputDirectory = "." + Path.DirectorySeparatorChar;
+ FilePath outputDirectory = "." + Path.DirectorySeparatorChar;
public virtual FilePath OutputDirectory {
get { return outputDirectory; }
set { outputDirectory = value; }
}
- [ItemProperty("DebugSymbols", DefaultValue = false)]
- private bool debugMode = false;
+ bool debugMode = false;
public bool DebugMode {
get { return debugMode; }
set { debugMode = value; }
}
- [ItemProperty("ConsolePause", DefaultValue = true)]
- private bool pauseConsoleOutput = true;
+ bool pauseConsoleOutput = true;
public bool PauseConsoleOutput {
get { return pauseConsoleOutput; }
set { pauseConsoleOutput = value; }
}
- [ItemProperty("Externalconsole", DefaultValue = false)]
- private bool externalConsole = false;
+ bool externalConsole = false;
public bool ExternalConsole {
get { return externalConsole; }
set { externalConsole = value; }
}
- [ItemProperty("Commandlineparameters", DefaultValue = "")]
- private string commandLineParameters = "";
+ string commandLineParameters = "";
public string CommandLineParameters {
get { return commandLineParameters; }
set { commandLineParameters = value; }
}
- [ItemProperty("EnvironmentVariables", SkipEmpty = true)]
- [ItemProperty("Variable", Scope = "item")]
- [ItemProperty("name", Scope = "key")]
- [ItemProperty("value", Scope = "value")]
- private Dictionary<string, string> environmentVariables = new Dictionary<string, string> ();
+ Dictionary<string, string> environmentVariables = new Dictionary<string, string> ();
public Dictionary<string, string> EnvironmentVariables {
get { return environmentVariables; }
}
@@ -122,8 +171,7 @@ namespace MonoDevelop.Projects
return vars;
}
- [ItemProperty("RunWithWarnings", DefaultValue = true)]
- private bool runWithWarnings = true;
+ bool runWithWarnings = true;
public virtual bool RunWithWarnings {
get { return runWithWarnings; }
set { runWithWarnings = value; }
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConvertTool.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConvertTool.cs
index 6bedef9308..c849d3b8d0 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConvertTool.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectConvertTool.cs
@@ -177,7 +177,10 @@ namespace MonoDevelop.Projects
destPath = Path.GetDirectoryName (projectFile);
destPath = FileService.GetFullPath (destPath);
- string ofile = Services.ProjectService.Export (monitor, projectFile, itemsToExport, destPath, format);
+ var t = Services.ProjectService.Export (monitor, projectFile, itemsToExport, destPath, format);
+ t.Wait ();
+ string ofile = t.Result;
+
if (ofile != null) {
Console.WriteLine ("Saved file: " + ofile);
return 0;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs
new file mode 100644
index 0000000000..a1dd21715c
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs
@@ -0,0 +1,182 @@
+//
+// MSBuildProjectExtension.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using MonoDevelop.Core;
+using System.Threading.Tasks;
+using MonoDevelop.Projects.Formats.MSBuild;
+using Mono.Addins;
+using System.Linq;
+
+namespace MonoDevelop.Projects
+{
+ public class ProjectExtension: SolutionItemExtension
+ {
+ ProjectExtension next;
+
+ public Project Project {
+ get { return (Project) base.Item; }
+ }
+
+ internal protected override void InitializeChain (ChainedExtension next)
+ {
+ base.InitializeChain (next);
+ this.next = FindNextImplementation<ProjectExtension> (next);
+ }
+
+ internal protected override bool SupportsObject (WorkspaceObject item)
+ {
+ return item is Project && base.SupportsObject (item);
+ }
+
+ internal protected virtual bool SupportsFlavor (string guid)
+ {
+ if (FlavorGuid != null && guid.Equals (FlavorGuid, StringComparison.OrdinalIgnoreCase))
+ return true;
+ return next.SupportsFlavor (guid);
+ }
+
+ internal protected virtual Task<BuildResult> OnRunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ {
+ return next.OnRunTarget (monitor, target, configuration);
+ }
+
+ internal protected virtual bool OnGetSupportsTarget (string target)
+ {
+ return next.OnGetSupportsTarget (target);
+ }
+
+ internal protected virtual void OnGetProjectTypes (HashSet<string> types)
+ {
+ next.OnGetProjectTypes (types);
+ }
+
+ internal protected virtual void OnReadProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ next.OnReadProject (monitor, msproject);
+ }
+
+ internal protected virtual void OnReadConfiguration (ProgressMonitor monitor, ProjectConfiguration config, IMSBuildPropertySet pset)
+ {
+ next.OnReadConfiguration (monitor, config, pset);
+ }
+
+ internal protected virtual void OnWriteProject (ProgressMonitor monitor, MSBuildProject msproject)
+ {
+ next.OnWriteProject (monitor, msproject);
+ }
+
+ internal protected virtual void OnWriteConfiguration (ProgressMonitor monitor, ProjectConfiguration config, IMSBuildPropertySet pset)
+ {
+ next.OnWriteConfiguration (monitor, config, pset);
+ }
+
+ #region Building
+
+ internal protected virtual bool OnGetIsCompileable (string fileName)
+ {
+ return next.OnGetIsCompileable (fileName);
+ }
+
+ internal protected virtual string OnGetDefaultBuildAction (string fileName)
+ {
+ return next.OnGetDefaultBuildAction (fileName);
+ }
+
+ internal protected virtual string OnGetDefaultResourceId (ProjectFile projectFile)
+ {
+ return next.OnGetDefaultResourceId (projectFile);
+ }
+
+ internal protected virtual IEnumerable<string> OnGetStandardBuildActions ()
+ {
+ return next.OnGetStandardBuildActions ();
+ }
+
+ internal protected virtual IList<string> OnGetCommonBuildActions ()
+ {
+ return next.OnGetCommonBuildActions ();
+ }
+
+ internal protected virtual ProjectItem OnCreateProjectItem (IMSBuildItemEvaluated item)
+ {
+ return next.OnCreateProjectItem (item);
+ }
+
+ internal protected virtual void OnPopulateSupportFileList (FileCopySet list, ConfigurationSelector configuration)
+ {
+ next.OnPopulateSupportFileList (list, configuration);
+ }
+
+ internal protected virtual void OnPopulateOutputFileList (List<FilePath> list, ConfigurationSelector configuration)
+ {
+ next.OnPopulateOutputFileList (list, configuration);
+ }
+
+ internal protected virtual FilePath OnGetOutputFileName (ConfigurationSelector configuration)
+ {
+ return next.OnGetOutputFileName (configuration);
+ }
+
+ internal protected virtual string[] SupportedLanguages {
+ get {
+ return next.SupportedLanguages;
+ }
+ }
+
+ #endregion
+
+ #region Events
+
+ internal protected virtual void OnFileRemovedFromProject (ProjectFileEventArgs e)
+ {
+ next.OnFileRemovedFromProject (e);
+ }
+
+ internal protected virtual void OnFileAddedToProject (ProjectFileEventArgs e)
+ {
+ next.OnFileAddedToProject (e);
+ }
+
+ internal protected virtual void OnFileChangedInProject (ProjectFileEventArgs e)
+ {
+ next.OnFileChangedInProject (e);
+ }
+
+ internal protected virtual void OnFilePropertyChangedInProject (ProjectFileEventArgs e)
+ {
+ next.OnFilePropertyChangedInProject (e);
+ }
+
+ internal protected virtual void OnFileRenamedInProject (ProjectFileRenamedEventArgs e)
+ {
+ next.OnFileRenamedInProject (e);
+ }
+
+ #endregion
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs
index 77d9f63534..ad7d99b972 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFile.cs
@@ -37,6 +37,7 @@ using MonoDevelop.Core;
using MonoDevelop.Core.Serialization;
using MonoDevelop.Projects;
using MonoDevelop.Projects.Extensions;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
@@ -55,21 +56,98 @@ namespace MonoDevelop.Projects
{
}
- public ProjectFile (string filename)
+ public ProjectFile (string filename): this (filename, MonoDevelop.Projects.BuildAction.Compile)
{
- this.filename = FileService.GetFullPath (filename);
- subtype = Subtype.Code;
- buildaction = MonoDevelop.Projects.BuildAction.Compile;
}
public ProjectFile (string filename, string buildAction)
{
this.filename = FileService.GetFullPath (filename);
subtype = Subtype.Code;
- buildaction = buildAction;
+ ItemName = buildaction = buildAction;
+ }
+
+ public override string Include {
+ get {
+ if (project != null) {
+ string path = MSBuildProjectService.ToMSBuildPath (project.ItemDirectory, FilePath);
+ if (path.Length > 0) {
+ //directory paths must end with '/'
+ if ((Subtype == Subtype.Directory) && path [path.Length - 1] != '\\')
+ path = path + "\\";
+ return path;
+ }
+ }
+ return base.Include;
+ }
+ protected set {
+ base.Include = value;
+ }
+ }
+
+ internal protected override void Read (Project project, IMSBuildItemEvaluated buildItem)
+ {
+ base.Read (project, buildItem);
+
+ if (buildItem.Name == "Folder") {
+ // Read folders
+ string path = MSBuildProjectService.FromMSBuildPath (project.ItemDirectory, buildItem.Include);
+ Name = Path.GetDirectoryName (path);
+ Subtype = Subtype.Directory;
+ return;
+ }
+
+ Name = MSBuildProjectService.FromMSBuildPath (project.ItemDirectory, buildItem.Include);
+ BuildAction = buildItem.Name;
+
+ DependsOn = buildItem.Metadata.GetPathValue ("DependentUpon", relativeToPath:FilePath.ParentDirectory);
+
+ string copy = buildItem.Metadata.GetValue ("CopyToOutputDirectory");
+ if (!string.IsNullOrEmpty (copy)) {
+ switch (copy) {
+ case "None": break;
+ case "Always": CopyToOutputDirectory = FileCopyMode.Always; break;
+ case "PreserveNewest": CopyToOutputDirectory = FileCopyMode.PreserveNewest; break;
+ default:
+ LoggingService.LogWarning (
+ "Unrecognised value {0} for CopyToOutputDirectory MSBuild property",
+ copy);
+ break;
+ }
+ }
+
+ Visible = buildItem.Metadata.GetValue ("Visible", true);
+ resourceId = buildItem.Metadata.GetValue ("LogicalName");
+ contentType = buildItem.Metadata.GetValue ("SubType");
+ generator = buildItem.Metadata.GetValue ("Generator");
+ customToolNamespace = buildItem.Metadata.GetValue ("CustomToolNamespace");
+ lastGenOutput = buildItem.Metadata.GetValue ("LastGenOutput");
+ Link = buildItem.Metadata.GetPathValue ("Link", relativeToProject:false);
}
- [ItemProperty("subtype")]
+ internal protected override void Write (MSBuildFileFormat fmt, MSBuildItem buildItem)
+ {
+ base.Write (fmt, buildItem);
+
+ buildItem.Metadata.SetValue ("DependentUpon", DependsOn, FilePath.Empty, relativeToPath:FilePath.ParentDirectory);
+ buildItem.Metadata.SetValue ("SubType", ContentType, "");
+ buildItem.Metadata.SetValue ("Generator", Generator, "");
+ buildItem.Metadata.SetValue ("CustomToolNamespace", CustomToolNamespace, "");
+ buildItem.Metadata.SetValue ("LastGenOutput", LastGenOutput, "");
+ buildItem.Metadata.SetValue ("Link", Link, FilePath.Empty, relativeToProject:false);
+ buildItem.Metadata.SetValue ("CopyToOutputDirectory", CopyToOutputDirectory.ToString (), "None");
+ buildItem.Metadata.SetValue ("Visible", Visible, true);
+
+ var resId = ResourceId;
+
+ //For EmbeddedResource, emit LogicalName only when it does not match the default Id
+ if (BuildAction == MonoDevelop.Projects.BuildAction.EmbeddedResource && project.GetDefaultResourceId (this) == resId)
+ resId = "";
+
+ buildItem.Metadata.SetValue ("LogicalName", resId, "");
+ }
+
+
Subtype subtype;
public Subtype Subtype {
get { return subtype; }
@@ -79,17 +157,6 @@ namespace MonoDevelop.Projects
}
}
- [ItemProperty("data", DefaultValue = "")]
- string data = "";
- public string Data {
- get { return data; }
- set {
- data = value;
- OnChanged ("Data");
- }
- }
-
-
public string Name {
get { return filename; }
@@ -117,8 +184,6 @@ namespace MonoDevelop.Projects
}
}
-
- [ItemProperty("buildaction")]
string buildaction = MonoDevelop.Projects.BuildAction.None;
public string BuildAction {
get { return buildaction; }
@@ -128,7 +193,6 @@ namespace MonoDevelop.Projects
}
}
- [ItemProperty("resource_id", DefaultValue = "")]
string resourceId = String.Empty;
internal string GetResourceId (IResourceHandler resourceHandler)
@@ -148,15 +212,6 @@ namespace MonoDevelop.Projects
}
/// <summary>
- /// Set to true if this ProjectFile was created at load time by
- /// a ProjectFile containing wildcards. If true, this instance
- /// should not be saved to a csproj file.
- /// </summary>
- internal bool IsOriginatedFromWildcard {
- get; set;
- }
-
- /// <summary>
/// The file should be treated as effectively having this relative path within the project. If the file is
/// a link or outside the project root, this will not be the same as the physical file.
/// </summary>
@@ -179,17 +234,15 @@ namespace MonoDevelop.Projects
get { return project; }
}
- [ItemProperty("SubType")]
- string contentType = String.Empty;
+ string contentType;
public string ContentType {
- get { return contentType; }
+ get { return contentType ?? ""; }
set {
contentType = value;
OnChanged ("ContentType");
}
}
- [ItemProperty("Visible", DefaultValue = true)]
bool visible = true;
/// <summary>
@@ -205,14 +258,13 @@ namespace MonoDevelop.Projects
}
}
- [ItemProperty("Generator", DefaultValue = "")]
string generator;
/// <summary>
/// The ID of a custom code generator.
/// </summary>
public string Generator {
- get { return generator; }
+ get { return generator ?? ""; }
set {
if (generator != value) {
generator = value;
@@ -221,14 +273,13 @@ namespace MonoDevelop.Projects
}
}
- [ItemProperty("CustomToolNamespace", DefaultValue = "")]
string customToolNamespace;
/// <summary>
/// Overrides the namespace in which the custom code generator should generate code.
/// </summary>
public string CustomToolNamespace {
- get { return customToolNamespace; }
+ get { return customToolNamespace ?? ""; }
set {
if (customToolNamespace != value) {
customToolNamespace = value;
@@ -238,14 +289,13 @@ namespace MonoDevelop.Projects
}
- [ItemProperty("LastGenOutput", DefaultValue = "")]
string lastGenOutput;
/// <summary>
/// The file most recently generated by the custom tool. Relative to this file's parent directory.
/// </summary>
public string LastGenOutput {
- get { return lastGenOutput; }
+ get { return lastGenOutput ?? ""; }
set {
if (lastGenOutput != value) {
lastGenOutput = value;
@@ -254,8 +304,6 @@ namespace MonoDevelop.Projects
}
}
-
- [RelativeProjectPathItemProperty("Link", DefaultValue = "")]
string link;
/// <summary>
@@ -263,7 +311,7 @@ namespace MonoDevelop.Projects
/// within the project root. Use ProjectVirtualPath to read the effective virtual path for any file.
/// </summary>
public FilePath Link {
- get { return link; }
+ get { return link ?? ""; }
set {
if (link != value) {
if (value.IsAbsolute || value.ToString ().StartsWith ("..", StringComparison.Ordinal))
@@ -296,8 +344,7 @@ namespace MonoDevelop.Projects
}
}
- [ItemProperty("copyToOutputDirectory", DefaultValue = FileCopyMode.None)]
- FileCopyMode copyToOutputDirectory;
+ FileCopyMode copyToOutputDirectory = FileCopyMode.None;
public FileCopyMode CopyToOutputDirectory {
get { return copyToOutputDirectory; }
set {
@@ -311,7 +358,7 @@ namespace MonoDevelop.Projects
#region File grouping
string dependsOn;
public string DependsOn {
- get { return dependsOn; }
+ get { return dependsOn ?? ""; }
set {
if (dependsOn != value) {
@@ -406,15 +453,18 @@ namespace MonoDevelop.Projects
return resourceId;
}
set {
- resourceId = value;
- OnChanged ("ResourceId");
+ if (resourceId != value) {
+ var oldVal = ResourceId;
+ resourceId = value;
+ if (ResourceId != oldVal)
+ OnChanged ("ResourceId");
+ }
}
}
internal void SetProject (Project project)
{
this.project = project;
-
if (project != null)
OnVirtualPathChanged (FilePath.Null, ProjectVirtualPath);
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItem.cs
index 8c5a7303fa..cb9934cd82 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItem.cs
@@ -26,14 +26,16 @@
using System;
using System.Collections;
+using System.Collections.Generic;
using MonoDevelop.Core.Serialization;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
public class ProjectItem: IExtendedDataItem
{
Hashtable extendedProperties;
-
+
public IDictionary ExtendedProperties {
get {
if (extendedProperties == null)
@@ -41,19 +43,42 @@ namespace MonoDevelop.Projects
return extendedProperties;
}
}
+
+ public void SetMetadata (string name, string value, bool isXml = false)
+ {
+ }
+
+ public string GetMetadata (string name, string defaultValue = null)
+ {
+ return null;
+ }
internal string Condition { get; set; }
+ public string ItemName { get; protected set; }
+
+ public virtual string Include { get; protected set; }
+
+ public string UnevaluatedInclude { get; protected set; }
+
public ProjectItemFlags Flags { get; set; }
+
+ internal protected virtual void Read (Project project, IMSBuildItemEvaluated buildItem)
+ {
+ ItemName = buildItem.Name;
+ Include = buildItem.Include;
+ UnevaluatedInclude = buildItem.UnevaluatedInclude;
+ Condition = buildItem.Condition;
+ }
+
+ internal protected virtual void Write (MSBuildFileFormat fmt, MSBuildItem buildItem)
+ {
+ buildItem.Condition = Condition;
+ }
}
public class UnknownProjectItem: ProjectItem
{
- public string ItemName { get; private set; }
-
- [ItemProperty ("Include")]
- public string Include { get; private set; }
-
public UnknownProjectItem (string name, string include)
{
this.ItemName = name;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemCollection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemCollection.cs
index cfdbd848dc..4a2badcff1 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemCollection.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemCollection.cs
@@ -37,7 +37,7 @@ namespace MonoDevelop.Projects
{
}
- internal ProjectItemCollection (SolutionEntityItem parent): base (parent)
+ internal ProjectItemCollection (SolutionItem parent): base (parent)
{
}
}
@@ -51,11 +51,11 @@ namespace MonoDevelop.Projects
public class ProjectItemCollection<T>: ItemCollection<T>, IItemListHandler where T: ProjectItem
{
- SolutionEntityItem parent;
+ SolutionItem parent;
IItemListHandler parentCollection;
List<IItemListHandler> subCollections;
- internal ProjectItemCollection (SolutionEntityItem parent)
+ internal ProjectItemCollection (SolutionItem parent)
{
this.parent = parent;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemEventArgs.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemEventArgs.cs
index 50cbb2dd8e..806c633362 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemEventArgs.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectItemEventArgs.cs
@@ -34,7 +34,7 @@ namespace MonoDevelop.Projects
{
}
- public ProjectItemEventArgs (SolutionEntityItem solutionItem, ProjectItem item)
+ public ProjectItemEventArgs (SolutionItem solutionItem, ProjectItem item)
{
Add (new ProjectItemEventInfo (solutionItem, item));
}
@@ -43,15 +43,15 @@ namespace MonoDevelop.Projects
public class ProjectItemEventInfo
{
ProjectItem item;
- SolutionEntityItem solutionItem;
+ SolutionItem solutionItem;
- public ProjectItemEventInfo (SolutionEntityItem solutionItem, ProjectItem item)
+ public ProjectItemEventInfo (SolutionItem solutionItem, ProjectItem item)
{
this.item = item;
this.solutionItem = solutionItem;
}
- public SolutionEntityItem SolutionItem {
+ public SolutionItem SolutionItem {
get {
return solutionItem;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectParameters.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectParameters.cs
index 457111b18d..f78e021bc7 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectParameters.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectParameters.cs
@@ -27,11 +27,12 @@
using System;
using MonoDevelop.Core.Serialization;
using MonoDevelop.Projects.Extensions;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
[DataItem (FallbackType=typeof(UnknownProjectParameters))]
- public class ProjectParameters: ILoadController
+ public class ProjectParameters: ILoadController, IMSBuildDataObject
{
DotNetProject parentProject;
@@ -69,5 +70,23 @@ namespace MonoDevelop.Projects
protected virtual void OnEndLoad ()
{
}
+
+ void IMSBuildDataObject.Read (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ Read (pset, format);
+ }
+
+ void IMSBuildDataObject.Write (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ Write (pset, format);
+ }
+
+ protected virtual void Read (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ }
+
+ protected virtual void Write (IMSBuildPropertySet pset, MSBuildFileFormat format)
+ {
+ }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectReference.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectReference.cs
index 74e56794d8..a30115c441 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectReference.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectReference.cs
@@ -37,6 +37,7 @@ using System.ComponentModel;
using MonoDevelop.Projects;
using MonoDevelop.Core.Serialization;
using MonoDevelop.Core.Assemblies;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
@@ -73,8 +74,11 @@ namespace MonoDevelop.Projects
string package;
SystemPackage cachedPackage;
string customError;
- string hintPath;
-
+ FilePath hintPath;
+
+ string originalMSBuildReferenceInclude;
+ string originalMSBuildReferenceHintPath;
+
public event EventHandler StatusChanged;
[ItemProperty ("Package", DefaultValue="")]
@@ -100,6 +104,19 @@ namespace MonoDevelop.Projects
ownerProject = project;
UpdatePackageReference ();
}
+
+ public sealed override string Include {
+ get {
+ if (referenceType == ReferenceType.Project && base.Include == null) {
+ Project refProj = OwnerProject != null && OwnerProject.ParentSolution != null ? OwnerProject.ParentSolution.FindProjectByName (Reference) : null;
+ if (refProj != null)
+ base.Include = MSBuildProjectService.ToMSBuildPath (OwnerProject.ItemDirectory, refProj.FileName);
+ else
+ base.Include = Reference;
+ }
+ return base.Include;
+ }
+ }
public ProjectReference (ReferenceType referenceType, string reference): this (referenceType, reference, null)
{
@@ -107,20 +124,66 @@ namespace MonoDevelop.Projects
public ProjectReference (ReferenceType referenceType, string reference, string hintPath)
{
+ Init (referenceType, reference, hintPath);
+ }
+
+ void Init (ReferenceType referenceType, string reference, string hintPath)
+ {
if (referenceType == ReferenceType.Assembly) {
specificVersion = false;
if (hintPath == null) {
hintPath = reference;
reference = Path.GetFileNameWithoutExtension (reference);
}
+
+ if (Include == null) {
+ if (File.Exists (HintPath)) {
+ try {
+ var aname = System.Reflection.AssemblyName.GetAssemblyName (HintPath);
+ if (SpecificVersion) {
+ Include = aname.FullName;
+ } else {
+ Include = aname.Name;
+ }
+ } catch (Exception ex) {
+ string msg = string.Format ("Could not get full name for assembly '{0}'.", Reference);
+ LoggingService.LogError (msg, ex);
+ }
+ }
+ if (Include == null)
+ Include = Path.GetFileNameWithoutExtension (hintPath);
+ }
+ }
+
+ switch (referenceType) {
+ case ReferenceType.Package:
+ case ReferenceType.Assembly:
+ ItemName = "Reference";
+ break;
+ case ReferenceType.Project:
+ ItemName = "ProjectReference";
+ break;
}
this.referenceType = referenceType;
this.reference = reference;
this.hintPath = hintPath;
UpdatePackageReference ();
+
+ if (referenceType == ReferenceType.Package && Include == null) {
+ Include = StoredReference;
+ SystemPackage pkg = Package;
+ if (pkg != null && pkg.IsFrameworkPackage) {
+ int i = Include.IndexOf (',');
+ if (i != -1)
+ Include = Include.Substring (0, i).Trim ();
+ }
+ }
+
+ if (Include == null)
+ Include = reference;
}
-
+
public ProjectReference (Project referencedProject)
{
referenceType = ReferenceType.Project;
@@ -138,7 +201,120 @@ namespace MonoDevelop.Projects
package = asm.Package.Name;
UpdatePackageReference ();
}
-
+
+ internal protected override void Read (Project project, IMSBuildItemEvaluated buildItem)
+ {
+ base.Read (project, buildItem);
+
+ if (buildItem.Name == "Reference")
+ ReadReference (project, buildItem);
+ else if (buildItem.Name == "ProjectReference")
+ ReadProjectReference (project, buildItem);
+
+ LocalCopy = buildItem.Metadata.GetValue ("Private", DefaultLocalCopy);
+ }
+
+ void ReadReference (Project project, IMSBuildItemEvaluated buildItem)
+ {
+ if (buildItem.Metadata.HasProperty ("HintPath")) {
+ FilePath path;
+ var p = buildItem.Metadata.GetProperty ("HintPath");
+ if (p != null)
+ originalMSBuildReferenceHintPath = p.UnevaluatedValue;
+ if (!buildItem.Metadata.TryGetPathValue ("HintPath", out path)) {
+ var hp = buildItem.Metadata.GetValue ("HintPath");
+ Init (ReferenceType.Assembly, hp, null);
+ SetInvalid (GettextCatalog.GetString ("Invalid file path"));
+ originalMSBuildReferenceInclude = buildItem.Include;
+ } else {
+ var type = File.Exists (path) ? ReferenceType.Assembly : ReferenceType.Package;
+ Init (type, buildItem.Include, path);
+ }
+ } else {
+ string asm = buildItem.Include;
+ // This is a workaround for a VS bug. Looks like it is writing this assembly incorrectly
+ if (asm == "System.configuration")
+ asm = "System.Configuration";
+ else if (asm == "System.XML")
+ asm = "System.Xml";
+ else if (asm == "system")
+ asm = "System";
+ Init (ReferenceType.Package, asm, null);
+ }
+
+ string specificVersion = buildItem.Metadata.GetValue ("SpecificVersion");
+ if (string.IsNullOrWhiteSpace (specificVersion)) {
+ // If the SpecificVersion element isn't present, check if the Assembly Reference specifies a Version
+ SpecificVersion = ReferenceStringHasVersion (buildItem.Include);
+ }
+ else {
+ bool value;
+ // if we can't parse the value, default to false which is more permissive
+ SpecificVersion = bool.TryParse (specificVersion, out value) && value;
+ }
+ }
+
+ void ReadProjectReference (Project project, IMSBuildItemEvaluated buildItem)
+ {
+ // Get the project name from the path, since the Name attribute may other stuff other than the name
+ string path = MSBuildProjectService.FromMSBuildPath (project.ItemDirectory, buildItem.Include);
+ string name = Path.GetFileNameWithoutExtension (path);
+ Init (ReferenceType.Project, name, null);
+ }
+
+ internal protected override void Write (MSBuildFileFormat fmt, MSBuildItem buildItem)
+ {
+ // If the project is not supported, don't try to update any metadata of the property,
+ // just leave what was read
+ if (OwnerProject.IsUnsupportedProject)
+ return;
+
+ base.Write (fmt, buildItem);
+
+ if (ReferenceType == ReferenceType.Assembly) {
+ if (originalMSBuildReferenceHintPath != null)
+ buildItem.Metadata.SetValue ("HintPath", originalMSBuildReferenceHintPath, "");
+ else
+ buildItem.Metadata.SetValue ("HintPath", HintPath);
+
+ buildItem.Metadata.SetValue ("SpecificVersion", SpecificVersion || !ReferenceStringHasVersion (Include), true);
+ }
+ else if (ReferenceType == ReferenceType.Package) {
+ buildItem.Metadata.SetValue ("SpecificVersion", SpecificVersion || !ReferenceStringHasVersion (Include), true);
+
+ //RequiredTargetFramework is undocumented, maybe only a hint for VS. Only seems to be used for .NETFramework
+ var dnp = OwnerProject as DotNetProject;
+ IList supportedFrameworks = fmt.SupportedFrameworks;
+ if (supportedFrameworks != null && dnp != null && Package != null
+ && dnp.TargetFramework.Id.Identifier == TargetFrameworkMoniker.ID_NET_FRAMEWORK
+ && Package.IsFrameworkPackage && supportedFrameworks.Contains (Package.TargetFramework)
+ && Package.TargetFramework.Version != "2.0" && supportedFrameworks.Count > 1)
+ {
+ TargetFramework fx = Runtime.SystemAssemblyService.GetTargetFramework (Package.TargetFramework);
+ buildItem.Metadata.SetValue ("RequiredTargetFramework", fx.Id.Version);
+ } else {
+ buildItem.Metadata.RemoveProperty ("RequiredTargetFramework");
+ }
+
+ buildItem.Metadata.SetValue ("HintPath", originalMSBuildReferenceHintPath, "");
+ }
+ else if (ReferenceType == ReferenceType.Project) {
+ Project refProj = OwnerProject.ParentSolution.FindProjectByName (Reference);
+ if (refProj != null) {
+ buildItem.Metadata.SetValue ("Project", refProj.ItemId);
+ buildItem.Metadata.SetValue ("Name", refProj.Name);
+ }
+ }
+
+ buildItem.Metadata.SetValue ("Private", LocalCopy, DefaultLocalCopy);
+ }
+
+ bool ReferenceStringHasVersion (string asmName)
+ {
+ int commaPos = asmName.IndexOf (',');
+ return commaPos >= 0 && asmName.IndexOf ("Version", commaPos) >= 0;
+ }
+
protected void InitCustomReference (string reference)
{
Reference = reference;
@@ -256,8 +432,7 @@ namespace MonoDevelop.Projects
if (notFound) {
if (ownerProject != null) {
bool isDefaultRuntime = Runtime.SystemAssemblyService.DefaultRuntime == TargetRuntime;
- var hintPath = ExtendedProperties ["_OriginalMSBuildReferenceHintPath"] as string;
- bool probablyFrameworkAssembly = string.IsNullOrEmpty (hintPath);
+ bool probablyFrameworkAssembly = string.IsNullOrEmpty (originalMSBuildReferenceHintPath);
if (TargetRuntime.IsInstalled (TargetFramework) || !probablyFrameworkAssembly) {
if (isDefaultRuntime)
@@ -307,7 +482,7 @@ namespace MonoDevelop.Projects
}
}
- public string HintPath {
+ public FilePath HintPath {
get { return hintPath; }
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
index 64d8bc6e76..fa493fb8f7 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
@@ -26,28 +26,22 @@
using System;
using System.Collections;
-using System.Collections.Specialized;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Xml;
-using System.CodeDom.Compiler;
-using System.Threading;
using MonoDevelop.Projects;
using MonoDevelop.Core.Serialization;
using MonoDevelop.Core;
using Mono.Addins;
-using MonoDevelop.Core.ProgressMonitoring;
-using MonoDevelop.Core.Execution;
using MonoDevelop.Core.Assemblies;
using MonoDevelop.Core.Instrumentation;
using MonoDevelop.Projects.Extensions;
using Mono.Unix;
-using MonoDevelop.Core.StringParsing;
using System.Linq;
using MonoDevelop.Projects.Formats.MSBuild;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
@@ -63,7 +57,7 @@ namespace MonoDevelop.Projects
TargetFramework defaultTargetFramework;
string defaultPlatformTarget = "x86";
- static readonly TargetFrameworkMoniker DefaultTargetFrameworkId = TargetFrameworkMoniker.NET_4_0;
+ static readonly TargetFrameworkMoniker DefaultTargetFrameworkId = TargetFrameworkMoniker.NET_4_5;
public const string BuildTarget = "Build";
public const string CleanTarget = "Clean";
@@ -72,7 +66,9 @@ namespace MonoDevelop.Projects
const string SerializableClassesExtensionPath = "/MonoDevelop/ProjectModel/SerializableClasses";
const string ExtendedPropertiesExtensionPath = "/MonoDevelop/ProjectModel/ExtendedProperties";
const string ProjectBindingsExtensionPath = "/MonoDevelop/ProjectModel/ProjectBindings";
-
+
+ internal const string ProjectModelExtensionsPath = "/MonoDevelop/ProjectModel/ProjectModelExtensions";
+
internal event EventHandler DataContextChanged;
class ExtensionChainInfo
@@ -101,7 +97,7 @@ namespace MonoDevelop.Projects
get { return formatManager; }
}
- internal ProjectServiceExtension GetExtensionChain (IBuildTarget target)
+ internal ProjectServiceExtension GetExtensionChain (WorkspaceObject target)
{
ProjectServiceExtension chain;
if (target != null) {
@@ -147,18 +143,14 @@ namespace MonoDevelop.Projects
ProjectServiceExtension CreateExtensionChain (ProjectServiceExtension[] extensions)
{
- var first = new CustomCommandExtension ();
-
- for (int n=0; n<extensions.Length - 1; n++)
- extensions [n].Next = extensions [n + 1];
-
if (extensions.Length > 0) {
+ for (int n=0; n<extensions.Length - 1; n++)
+ extensions [n].Next = extensions [n + 1];
extensions [extensions.Length - 1].Next = extensionChainTerminator;
- first.Next = extensions [0];
+ return extensions [0];
} else {
- first.Next = extensionChainTerminator;
+ return extensionChainTerminator;
}
- return first;
}
public string DefaultPlatformTarget {
@@ -191,16 +183,16 @@ namespace MonoDevelop.Projects
return formats [0];
}
- public SolutionEntityItem ReadSolutionItem (IProgressMonitor monitor, string file)
+ public async Task<SolutionItem> ReadSolutionItem (ProgressMonitor monitor, string file)
{
file = Path.GetFullPath (file);
using (Counters.ReadSolutionItem.BeginTiming ("Read project " + file)) {
file = GetTargetFile (file);
- SolutionEntityItem loadedItem = GetExtensionChain (null).LoadSolutionItem (monitor, file, delegate {
- FileFormat format;
- SolutionEntityItem item = ReadFile (monitor, file, typeof(SolutionEntityItem), out format) as SolutionEntityItem;
+ SolutionItem loadedItem = await GetExtensionChain (null).LoadSolutionItem (monitor, file, async delegate {
+ var res = await ReadFile (monitor, file, typeof(SolutionItem));
+ SolutionItem item = res.Item1 as SolutionItem;
if (item != null)
- item.FileFormat = format;
+ item.FileFormat = res.Item2;
else
throw new InvalidOperationException ("Invalid file format: " + file);
return item;
@@ -210,23 +202,23 @@ namespace MonoDevelop.Projects
}
}
- public SolutionItem ReadSolutionItem (IProgressMonitor monitor, SolutionItemReference reference, params WorkspaceItem[] workspaces)
+ public async Task<SolutionFolderItem> ReadSolutionItem (ProgressMonitor monitor, SolutionItemReference reference, params WorkspaceItem[] workspaces)
{
if (reference.Id == null) {
FilePath file = reference.Path.FullPath;
foreach (WorkspaceItem workspace in workspaces) {
- foreach (SolutionEntityItem eitem in workspace.GetAllSolutionItems<SolutionEntityItem> ())
+ foreach (SolutionItem eitem in workspace.GetAllItems<Solution>().SelectMany (s => s.GetAllSolutionItems ()))
if (file == eitem.FileName)
return eitem;
}
- return ReadSolutionItem (monitor, reference.Path);
+ return await ReadSolutionItem (monitor, reference.Path);
}
else {
Solution sol = null;
if (workspaces.Length > 0) {
FilePath file = reference.Path.FullPath;
foreach (WorkspaceItem workspace in workspaces) {
- foreach (Solution item in workspace.GetAllSolutions ()) {
+ foreach (Solution item in workspace.GetAllItems<Solution>()) {
if (item.FileName.FullPath == file) {
sol = item;
break;
@@ -237,7 +229,7 @@ namespace MonoDevelop.Projects
}
}
if (sol == null)
- sol = ReadWorkspaceItem (monitor, reference.Path) as Solution;
+ sol = await ReadWorkspaceItem (monitor, reference.Path) as Solution;
if (reference.Id == ":root:")
return sol.RootFolder;
@@ -246,12 +238,12 @@ namespace MonoDevelop.Projects
}
}
- public WorkspaceItem ReadWorkspaceItem (IProgressMonitor monitor, string file)
+ public async Task<WorkspaceItem> ReadWorkspaceItem (ProgressMonitor monitor, string file)
{
file = Path.GetFullPath (file);
using (Counters.ReadWorkspaceItem.BeginTiming ("Read solution " + file)) {
file = GetTargetFile (file);
- WorkspaceItem item = GetExtensionChain (null).LoadWorkspaceItem (monitor, file) as WorkspaceItem;
+ WorkspaceItem item = await GetExtensionChain (null).LoadWorkspaceItem (monitor, file) as WorkspaceItem;
if (item != null)
item.NeedsReload = false;
else
@@ -260,54 +252,45 @@ namespace MonoDevelop.Projects
}
}
- internal void InternalWriteSolutionItem (IProgressMonitor monitor, FilePath file, SolutionEntityItem item)
- {
- var newFile = WriteFile (monitor, file, item, null);
- if (newFile != null)
- item.FileName = newFile;
- else
- throw new InvalidOperationException ("FileFormat not provided for solution item '" + item.Name + "'");
- }
-
- internal WorkspaceItem InternalReadWorkspaceItem (string file, IProgressMonitor monitor)
+ internal async Task<WorkspaceItem> InternalReadWorkspaceItem (string file, ProgressMonitor monitor)
{
- FileFormat format;
- WorkspaceItem item = ReadFile (monitor, file, typeof(WorkspaceItem), out format) as WorkspaceItem;
+ var res = await ReadFile (monitor, file, typeof(WorkspaceItem));
+ WorkspaceItem item = res.Item1 as WorkspaceItem;
if (item == null)
throw new InvalidOperationException ("Invalid file format: " + file);
if (!item.FormatSet)
- item.ConvertToFormat (format, false);
+ await item.ConvertToFormat (res.Item2, false);
return item;
}
- internal void InternalWriteWorkspaceItem (IProgressMonitor monitor, FilePath file, WorkspaceItem item)
+ internal async Task InternalWriteWorkspaceItem (ProgressMonitor monitor, FilePath file, WorkspaceItem item)
{
- var newFile = WriteFile (monitor, file, item, item.FileFormat);
+ var newFile = await WriteFile (monitor, file, item, item.FileFormat);
if (newFile != null)
item.FileName = newFile;
else
throw new InvalidOperationException ("FileFormat not provided for workspace item '" + item.Name + "'");
}
- object ReadFile (IProgressMonitor monitor, string file, Type expectedType, out FileFormat format)
+ async Task<Tuple<object,FileFormat>> ReadFile (ProgressMonitor monitor, string file, Type expectedType)
{
FileFormat[] formats = formatManager.GetFileFormats (file, expectedType);
if (formats.Length == 0)
throw new InvalidOperationException ("Unknown file format: " + file);
- format = formats [0];
- object obj = format.Format.ReadFile (file, expectedType, monitor);
+ var format = formats [0];
+ object obj = await format.Format.ReadFile (file, expectedType, monitor);
if (obj == null)
throw new InvalidOperationException ("Invalid file format: " + file);
- return obj;
+ return new Tuple<object,FileFormat> (obj, format);
}
- FilePath WriteFile (IProgressMonitor monitor, FilePath file, object item, FileFormat format)
+ async Task<FilePath> WriteFile (ProgressMonitor monitor, FilePath file, object item, FileFormat format)
{
if (format == null) {
if (defaultFormat.CanWrite (item))
@@ -325,33 +308,33 @@ namespace MonoDevelop.Projects
FileService.RequestFileEdit (file);
- format.Format.WriteFile (file, item, monitor);
+ await format.Format.WriteFile (file, item, monitor);
return file;
}
- public string Export (IProgressMonitor monitor, string rootSourceFile, string targetPath, FileFormat format)
+ public Task<string> Export (ProgressMonitor monitor, string rootSourceFile, string targetPath, FileFormat format)
{
rootSourceFile = GetTargetFile (rootSourceFile);
return Export (monitor, rootSourceFile, null, targetPath, format);
}
- public string Export (IProgressMonitor monitor, string rootSourceFile, string[] includedChildIds, string targetPath, FileFormat format)
+ public async Task<string> Export (ProgressMonitor monitor, string rootSourceFile, string[] includedChildIds, string targetPath, FileFormat format)
{
IWorkspaceFileObject obj;
if (IsWorkspaceItemFile (rootSourceFile)) {
- obj = ReadWorkspaceItem (monitor, rootSourceFile) as Solution;
+ obj = await ReadWorkspaceItem (monitor, rootSourceFile) as Solution;
} else {
- obj = ReadSolutionItem (monitor, rootSourceFile);
+ obj = await ReadSolutionItem (monitor, rootSourceFile);
if (obj == null)
throw new InvalidOperationException ("File is not a solution or project.");
}
using (obj) {
- return Export (monitor, obj, includedChildIds, targetPath, format);
+ return await Export (monitor, obj, includedChildIds, targetPath, format);
}
}
- string Export (IProgressMonitor monitor, IWorkspaceFileObject obj, string[] includedChildIds, string targetPath, FileFormat format)
+ async Task<string> Export (ProgressMonitor monitor, IWorkspaceFileObject obj, string[] includedChildIds, string targetPath, FileFormat format)
{
string rootSourceFile = obj.FileName;
string sourcePath = Path.GetFullPath (Path.GetDirectoryName (rootSourceFile));
@@ -363,17 +346,17 @@ namespace MonoDevelop.Projects
string newFile = Path.Combine (targetPath, Path.GetFileName (rootSourceFile));
if (IsWorkspaceItemFile (rootSourceFile))
- obj = ReadWorkspaceItem (monitor, newFile);
+ obj = await ReadWorkspaceItem (monitor, newFile);
else
- obj = (SolutionEntityItem) ReadSolutionItem (monitor, newFile);
+ obj = (SolutionItem) await ReadSolutionItem (monitor, newFile);
using (obj) {
- List<FilePath> oldFiles = obj.GetItemFiles (true);
+ var oldFiles = obj.GetItemFiles (true).ToList ();
ExcludeEntries (obj, includedChildIds);
if (format != null)
- obj.ConvertToFormat (format, true);
- obj.Save (monitor);
- List<FilePath> newFiles = obj.GetItemFiles (true);
+ await obj.ConvertToFormat (format, true);
+ await obj.SaveAsync (monitor);
+ var newFiles = obj.GetItemFiles (true);
foreach (FilePath f in newFiles) {
if (!f.IsChildPathOf (targetPath)) {
@@ -408,8 +391,8 @@ namespace MonoDevelop.Projects
using (obj) {
ExcludeEntries (obj, includedChildIds);
if (format != null)
- obj.ConvertToFormat (format, true);
- obj.Save (monitor);
+ await obj.ConvertToFormat (format, true);
+ await obj.SaveAsync (monitor);
return obj.FileName;
}
}
@@ -425,14 +408,14 @@ namespace MonoDevelop.Projects
foreach (string it in includedChildIds)
childIds [it] = it;
- foreach (SolutionItem item in sol.GetAllSolutionItems<SolutionItem> ()) {
+ foreach (SolutionFolderItem item in sol.GetAllItems<SolutionFolderItem> ()) {
if (!childIds.ContainsKey (item.ItemId) && item.ParentFolder != null)
item.ParentFolder.Items.Remove (item);
}
}
}
- bool CopyFiles (IProgressMonitor monitor, IWorkspaceFileObject obj, IEnumerable<FilePath> files, FilePath targetBasePath, bool ignoreExternalFiles)
+ bool CopyFiles (ProgressMonitor monitor, IWorkspaceFileObject obj, IEnumerable<FilePath> files, FilePath targetBasePath, bool ignoreExternalFiles)
{
FilePath baseDir = obj.BaseDirectory.FullPath;
foreach (FilePath file in files) {
@@ -465,51 +448,28 @@ namespace MonoDevelop.Projects
return true;
}
- public bool CanCreateSingleFileProject (string file)
+ public DotNetProject CreateDotNetProject (string language)
{
- foreach (ProjectBindingCodon projectBinding in projectBindings) {
- if (projectBinding.ProjectBinding.CanCreateSingleFileProject (file))
- return true;
- }
- return false;
+ string typeGuid = MSBuildProjectService.GetLanguageGuid (language);
+ return (DotNetProject) MSBuildProjectService.CreateSolutionItem (typeGuid);
}
-
- public Project CreateSingleFileProject (string file)
- {
- foreach (ProjectBindingCodon projectBinding in projectBindings) {
- if (projectBinding.ProjectBinding.CanCreateSingleFileProject (file)) {
- return projectBinding.ProjectBinding.CreateSingleFileProject (file);
- }
- }
- return null;
- }
-
- public Project CreateProject (string type, ProjectCreateInformation info, XmlElement projectOptions)
+
+ public Project CreateProject (string typeAlias, ProjectCreateInformation info, XmlElement projectOptions)
{
- foreach (ProjectBindingCodon projectBinding in projectBindings) {
- if (projectBinding.ProjectBinding.Name == type) {
- Project project = projectBinding.ProjectBinding.CreateProject (info, projectOptions);
- return project;
- }
- }
- throw new InvalidOperationException ("Project type '" + type + "' not found");
+ return MSBuildProjectService.CreateSolutionItem (typeAlias, info, projectOptions) as Project;
}
- public bool CanCreateProject (string type)
+ public bool CanCreateProject (string typeAlias, ProjectCreateInformation info, XmlElement projectOptions)
{
- foreach (ProjectBindingCodon projectBinding in projectBindings) {
- if (projectBinding.ProjectBinding.Name == type)
- return true;
- }
- return false;
+ return MSBuildProjectService.CanCreateSolutionItem (typeAlias, info, projectOptions);
}
//TODO: find solution that contains the project if possible
- public Solution GetWrapperSolution (IProgressMonitor monitor, string filename)
+ public async Task<Solution> GetWrapperSolution (ProgressMonitor monitor, string filename)
{
// First of all, check if a solution with the same name already exists
- FileFormat[] formats = Services.ProjectService.FileFormats.GetFileFormats (filename, typeof(SolutionEntityItem));
+ FileFormat[] formats = Services.ProjectService.FileFormats.GetFileFormats (filename, typeof(SolutionItem));
if (formats.Length == 0)
formats = new [] { DefaultFileFormat };
@@ -520,16 +480,16 @@ namespace MonoDevelop.Projects
string solFileName = solutionFileFormat.GetValidFileName (tempSolution, filename);
if (File.Exists (solFileName)) {
- return (Solution) Services.ProjectService.ReadWorkspaceItem (monitor, solFileName);
+ return (Solution) await Services.ProjectService.ReadWorkspaceItem (monitor, solFileName);
}
else {
// Create a temporary solution and add the project to the solution
tempSolution.SetLocation (Path.GetDirectoryName (filename), Path.GetFileNameWithoutExtension (filename));
- SolutionEntityItem sitem = Services.ProjectService.ReadSolutionItem (monitor, filename);
- tempSolution.ConvertToFormat (solutionFileFormat, false);
+ SolutionItem sitem = await Services.ProjectService.ReadSolutionItem (monitor, filename);
+ await tempSolution.ConvertToFormat (solutionFileFormat, false);
tempSolution.RootFolder.Items.Add (sitem);
tempSolution.CreateDefaultConfigurations ();
- tempSolution.Save (monitor);
+ await tempSolution.SaveAsync (monitor);
return tempSolution;
}
}
@@ -552,7 +512,7 @@ namespace MonoDevelop.Projects
internal bool IsSolutionItemFileInternal (string filename)
{
- return formatManager.GetFileFormats (filename, typeof(SolutionItem)).Length > 0;
+ return formatManager.GetFileFormats (filename, typeof(SolutionFolderItem)).Length > 0;
}
internal bool IsWorkspaceItemFileInternal (string filename)
@@ -634,34 +594,6 @@ namespace MonoDevelop.Projects
internal class DefaultProjectServiceExtension: ProjectServiceExtension
{
- Dictionary <SolutionItem,bool> needsBuildingCache;
-
- public override object GetService (SolutionItem item, Type type)
- {
- return item.OnGetService (type);
- }
-
- public override object GetService (WorkspaceItem item, Type type)
- {
- return item.OnGetService (type);
- }
-
- public override void Save (IProgressMonitor monitor, SolutionEntityItem entry)
- {
- FileService.RequestFileEdit (entry.GetItemFiles (false));
- entry.OnSave (monitor);
- }
-
- public override void Save (IProgressMonitor monitor, WorkspaceItem entry)
- {
- entry.OnSave (monitor);
- }
-
- public override List<FilePath> GetItemFiles (SolutionEntityItem entry, bool includeReferencedFiles)
- {
- return entry.OnGetItemFiles (includeReferencedFiles);
- }
-
public override bool IsSolutionItemFile (string filename)
{
return Services.ProjectService.IsSolutionItemFileInternal (filename);
@@ -672,152 +604,15 @@ namespace MonoDevelop.Projects
return Services.ProjectService.IsWorkspaceItemFileInternal (filename);
}
- internal override SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName, ItemLoadCallback callback)
+ internal override Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, string fileName, ItemLoadCallback callback)
{
return callback (monitor, fileName);
}
- public override WorkspaceItem LoadWorkspaceItem (IProgressMonitor monitor, string fileName)
+ public override Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName)
{
return Services.ProjectService.InternalReadWorkspaceItem (fileName, monitor);
}
-
- public override BuildResult RunTarget (IProgressMonitor monitor, IBuildTarget item, string target, ConfigurationSelector configuration)
- {
- BuildResult res;
- if (item is WorkspaceItem) {
- res = ((WorkspaceItem)item).OnRunTarget (monitor, target, configuration);
- }
- else if (item is SolutionItem)
- res = ((SolutionItem)item).OnRunTarget (monitor, target, configuration);
- else
- throw new InvalidOperationException ("Unknown item type: " + item);
-
- if (res != null)
- res.SourceTarget = item;
- return res;
- }
-
- public override bool SupportsTarget (IBuildTarget item, string target)
- {
- if (item is WorkspaceItem)
- return ((WorkspaceItem)item).OnGetSupportsTarget (target);
- else if (item is SolutionItem)
- return ((SolutionItem)item).OnGetSupportsTarget (target);
- else
- throw new InvalidOperationException ("Unknown item type: " + item);
- }
-
- public override bool SupportsExecute (IBuildTarget item)
- {
- if (item is WorkspaceItem)
- return ((WorkspaceItem)item).OnGetSupportsExecute ();
- else if (item is SolutionItem)
- return ((SolutionItem)item).OnGetSupportsExecute ();
- else
- throw new InvalidOperationException ("Unknown item type: " + item);
- }
-
- public override void Execute (IProgressMonitor monitor, IBuildTarget item, ExecutionContext context, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem) {
- SolutionEntityItem entry = (SolutionEntityItem) item;
- SolutionItemConfiguration conf = entry.GetConfiguration (configuration) as SolutionItemConfiguration;
- if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Execute)) {
- conf.CustomCommands.ExecuteCommand (monitor, entry, CustomCommandType.Execute, context, configuration);
- return;
- }
- entry.OnExecute (monitor, context, configuration);
- }
- else if (item is WorkspaceItem) {
- ((WorkspaceItem)item).OnExecute (monitor, context, configuration);
- }
- else if (item is SolutionItem)
- ((SolutionItem)item).OnExecute (monitor, context, configuration);
- else
- throw new InvalidOperationException ("Unknown item type: " + item);
- }
-
- public override bool CanExecute (IBuildTarget item, ExecutionContext context, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem) {
- SolutionEntityItem entry = (SolutionEntityItem) item;
- SolutionItemConfiguration conf = entry.GetConfiguration (configuration) as SolutionItemConfiguration;
- if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Execute))
- return conf.CustomCommands.CanExecute (entry, CustomCommandType.Execute, context, configuration);
- return entry.OnGetCanExecute (context, configuration);
- }
- else if (item is WorkspaceItem) {
- return ((WorkspaceItem)item).OnGetCanExecute (context, configuration);
- }
- else if (item is SolutionItem)
- return ((SolutionItem)item).OnGetCanExecute (context, configuration);
- else
- throw new InvalidOperationException ("Unknown item type: " + item);
- }
-
- public override IEnumerable<ExecutionTarget> GetExecutionTargets (IBuildTarget item, ConfigurationSelector configuration)
- {
- if (item is WorkspaceItem) {
- return ((WorkspaceItem)item).OnGetExecutionTargets (configuration);
- }
- else if (item is SolutionItem)
- return ((SolutionItem)item).OnGetExecutionTargets (configuration);
- else
- throw new InvalidOperationException ("Unknown item type: " + item);
- }
-
- public override bool GetNeedsBuilding (IBuildTarget item, ConfigurationSelector configuration)
- {
- if (item is SolutionItem) {
- SolutionItem entry = (SolutionItem) item;
- // This is a cache to avoid unneeded recursive calls to GetNeedsBuilding.
- bool cleanCache = false;
- if (needsBuildingCache == null) {
- needsBuildingCache = new Dictionary <SolutionItem,bool> ();
- cleanCache = true;
- } else {
- bool res;
- if (needsBuildingCache.TryGetValue (entry, out res))
- return res;
- }
-
- bool nb = entry.OnGetNeedsBuilding (configuration);
-
- needsBuildingCache [entry] = nb;
- if (cleanCache)
- needsBuildingCache = null;
- return nb;
- }
- else if (item is WorkspaceItem) {
- return ((WorkspaceItem)item).OnGetNeedsBuilding (configuration);
- }
- else
- throw new InvalidOperationException ("Unknown item type: " + item);
- }
-
- public override void SetNeedsBuilding (IBuildTarget item, bool val, ConfigurationSelector configuration)
- {
- if (item is SolutionItem) {
- SolutionItem entry = (SolutionItem) item;
- entry.OnSetNeedsBuilding (val, configuration);
- }
- else if (item is WorkspaceItem) {
- ((WorkspaceItem)item).OnSetNeedsBuilding (val, configuration);
- }
- else
- throw new InvalidOperationException ("Unknown item type: " + item);
- }
-
- internal override BuildResult Compile(IProgressMonitor monitor, SolutionEntityItem item, BuildData buildData, ItemCompileCallback callback)
- {
- return callback (monitor, item, buildData);
- }
-
- public override IEnumerable<string> GetReferencedAssemblies (DotNetProject project, ConfigurationSelector configuration, bool includeProjectReferences)
- {
- return project.OnGetReferencedAssemblies (configuration, includeProjectReferences);
- }
}
internal static class Counters
@@ -826,7 +621,7 @@ namespace MonoDevelop.Projects
public static Counter ItemsLoaded = InstrumentationService.CreateCounter ("Projects loaded", "Project Model");
public static Counter SolutionsInMemory = InstrumentationService.CreateCounter ("Solutions in memory", "Project Model");
public static Counter SolutionsLoaded = InstrumentationService.CreateCounter ("Solutions loaded", "Project Model");
- public static TimerCounter ReadWorkspaceItem = InstrumentationService.CreateTimerCounter ("Workspace item read", "Project Model");
+ public static TimerCounter ReadWorkspaceItem = InstrumentationService.CreateTimerCounter ("Workspace item read", "Project Model", id:"Core.ReadWorkspaceItem");
public static TimerCounter ReadSolutionItem = InstrumentationService.CreateTimerCounter ("Solution item read", "Project Model");
public static TimerCounter ReadMSBuildProject = InstrumentationService.CreateTimerCounter ("MSBuild project read", "Project Model");
public static TimerCounter WriteMSBuildProject = InstrumentationService.CreateTimerCounter ("MSBuild project written", "Project Model");
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectServiceExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectServiceExtension.cs
index 476081baf6..08d368c82e 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectServiceExtension.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectServiceExtension.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
using MonoDevelop.Core;
using MonoDevelop.Projects.Extensions;
using MonoDevelop.Core.Execution;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
@@ -39,9 +40,8 @@ namespace MonoDevelop.Projects
internal ProjectServiceExtension Next;
Stack<ItemLoadCallback> loadCallbackStack = new Stack<ItemLoadCallback> ();
- Stack<ItemCompileCallback> compileCallbackStack = new Stack<ItemCompileCallback> ();
-
- internal ProjectServiceExtension GetNext (IBuildTarget item)
+
+ internal ProjectServiceExtension GetNext (WorkspaceObject item)
{
if (Next.SupportsItem (item))
return Next;
@@ -49,42 +49,11 @@ namespace MonoDevelop.Projects
return Next.GetNext (item);
}
- public virtual bool SupportsItem (IBuildTarget item)
+ public virtual bool SupportsItem (WorkspaceObject item)
{
return true;
}
- public virtual object GetService (SolutionItem item, Type type)
- {
- if (type.IsInstanceOfType (this))
- return this;
- else
- return GetNext (item).GetService (item, type);
- }
-
- public virtual object GetService (WorkspaceItem item, Type type)
- {
- if (type.IsInstanceOfType (this))
- return this;
- else
- return GetNext (item).GetService (item, type);
- }
-
- public virtual void Save (IProgressMonitor monitor, SolutionEntityItem item)
- {
- GetNext (item).Save (monitor, item);
- }
-
- public virtual void Save (IProgressMonitor monitor, WorkspaceItem item)
- {
- GetNext (item).Save (monitor, item);
- }
-
- public virtual List<FilePath> GetItemFiles (SolutionEntityItem item, bool includeReferencedFiles)
- {
- return GetNext (item).GetItemFiles (item, includeReferencedFiles);
- }
-
public virtual bool IsSolutionItemFile (string fileName)
{
return GetNext (UnknownItem.Instance).IsSolutionItemFile (fileName);
@@ -95,307 +64,25 @@ namespace MonoDevelop.Projects
return GetNext (UnknownItem.Instance).IsWorkspaceItemFile (fileName);
}
- internal virtual SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName, ItemLoadCallback callback)
+ internal async virtual Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, string fileName, ItemLoadCallback callback)
{
loadCallbackStack.Push (callback);
try {
- SolutionEntityItem res = LoadSolutionItem (monitor, fileName);
- return res;
+ return await LoadSolutionItem (monitor, fileName);
} finally {
loadCallbackStack.Pop ();
}
}
- protected virtual SolutionEntityItem LoadSolutionItem (IProgressMonitor monitor, string fileName)
+ protected virtual Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, string fileName)
{
return GetNext (UnknownItem.Instance).LoadSolutionItem (monitor, fileName, loadCallbackStack.Peek ());
}
- public virtual WorkspaceItem LoadWorkspaceItem (IProgressMonitor monitor, string fileName)
+ public virtual Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName)
{
return GetNext (UnknownItem.Instance).LoadWorkspaceItem (monitor, fileName);
}
-
- public virtual BuildResult RunTarget (IProgressMonitor monitor, IBuildTarget item, string target, ConfigurationSelector configuration)
- {
- if (target == ProjectService.BuildTarget)
- return Build (monitor, item, configuration);
- else if (target == ProjectService.CleanTarget) {
- Clean (monitor, item, configuration);
- return null;
- }
- else
- return GetNext (item).RunTarget (monitor, item, target, configuration);
- }
-
- public virtual bool SupportsTarget (IBuildTarget item, string target)
- {
- if (item is SolutionEntityItem)
- return SupportsTarget ((SolutionEntityItem)item, target);
- else if (item is WorkspaceItem)
- return SupportsTarget ((WorkspaceItem) item, target);
- else
- return GetNext (item).SupportsTarget (item, target);
- }
-
- protected virtual bool SupportsTarget (SolutionEntityItem item, string target)
- {
- return GetNext (item).SupportsTarget ((IBuildTarget) item, target);
- }
-
- protected virtual bool SupportsTarget (Solution solution, string target)
- {
- return GetNext (solution).SupportsTarget ((IBuildTarget) solution, target);
- }
-
- protected virtual bool SupportsTarget (WorkspaceItem item, string target)
- {
- if (item is Solution)
- return SupportsTarget ((Solution) item, target);
- else
- return GetNext (item).SupportsTarget ((IBuildTarget) item, target);
- }
-
- public virtual bool SupportsExecute (IBuildTarget item)
- {
- if (item is SolutionEntityItem)
- return SupportsExecute ((SolutionEntityItem)item);
- else if (item is WorkspaceItem)
- return SupportsExecute ((WorkspaceItem) item);
- else
- return GetNext (item).SupportsExecute (item);
- }
-
- protected virtual bool SupportsExecute (SolutionEntityItem item)
- {
- return GetNext (item).SupportsExecute ((IBuildTarget) item);
- }
-
- protected virtual bool SupportsExecute (Solution solution)
- {
- return GetNext (solution).SupportsExecute ((IBuildTarget) solution);
- }
-
- protected virtual bool SupportsExecute (WorkspaceItem item)
- {
- if (item is Solution)
- return SupportsExecute ((Solution) item);
- else
- return GetNext (item).SupportsExecute ((IBuildTarget) item);
- }
-
- protected virtual void Clean (IProgressMonitor monitor, IBuildTarget item, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem)
- Clean (monitor, (SolutionEntityItem) item, configuration);
- else if (item is WorkspaceItem)
- Clean (monitor, (WorkspaceItem) item, configuration);
- else
- GetNext (item).RunTarget (monitor, item, ProjectService.CleanTarget, configuration);
- }
-
- protected virtual void Clean (IProgressMonitor monitor, SolutionEntityItem item, ConfigurationSelector configuration)
- {
- GetNext (item).RunTarget (monitor, item, ProjectService.CleanTarget, configuration);
- }
-
- protected virtual void Clean (IProgressMonitor monitor, Solution item, ConfigurationSelector configuration)
- {
- GetNext (item).RunTarget (monitor, item, ProjectService.CleanTarget, configuration);
- }
-
- protected virtual void Clean (IProgressMonitor monitor, WorkspaceItem item, ConfigurationSelector configuration)
- {
- if (item is Solution)
- Clean (monitor, (Solution) item, configuration);
- else
- GetNext (item).RunTarget (monitor, item, ProjectService.CleanTarget, configuration);
- }
-
- protected virtual BuildResult Build (IProgressMonitor monitor, IBuildTarget item, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem)
- return Build (monitor, (SolutionEntityItem) item, configuration);
- if (item is WorkspaceItem)
- return Build (monitor, (WorkspaceItem) item, configuration);
- return GetNext (item).RunTarget (monitor, item, ProjectService.BuildTarget, configuration);
- }
-
- protected virtual BuildResult Build (IProgressMonitor monitor, SolutionEntityItem item, ConfigurationSelector configuration)
- {
- return GetNext (item).RunTarget (monitor, item, ProjectService.BuildTarget, configuration);
- }
-
- protected virtual BuildResult Build (IProgressMonitor monitor, WorkspaceItem item, ConfigurationSelector configuration)
- {
- if (item is Solution)
- return Build (monitor, (Solution) item, configuration);
- return GetNext (item).RunTarget (monitor, item, ProjectService.BuildTarget, configuration);
- }
-
- protected virtual BuildResult Build (IProgressMonitor monitor, Solution solution, ConfigurationSelector configuration)
- {
- return GetNext (solution).RunTarget (monitor, solution, ProjectService.BuildTarget, configuration);
- }
-
- public virtual void Execute (IProgressMonitor monitor, IBuildTarget item, ExecutionContext context, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem)
- Execute (monitor, (SolutionEntityItem)item, context, configuration);
- else if (item is WorkspaceItem)
- Execute (monitor, (WorkspaceItem) item, context, configuration);
- else
- GetNext (item).Execute (monitor, item, context, configuration);
- }
-
- protected virtual void Execute (IProgressMonitor monitor, SolutionEntityItem item, ExecutionContext context, ConfigurationSelector configuration)
- {
- GetNext (item).Execute (monitor, (IBuildTarget) item, context, configuration);
- }
-
- protected virtual void Execute (IProgressMonitor monitor, Solution solution, ExecutionContext context, ConfigurationSelector configuration)
- {
- GetNext (solution).Execute (monitor, (IBuildTarget) solution, context, configuration);
- }
-
- protected virtual void Execute (IProgressMonitor monitor, WorkspaceItem item, ExecutionContext context, ConfigurationSelector configuration)
- {
- if (item is Solution)
- Execute (monitor, (Solution) item, context, configuration);
- else
- GetNext (item).Execute (monitor, (IBuildTarget) item, context, configuration);
- }
-
- public virtual bool CanExecute (IBuildTarget item, ExecutionContext context, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem)
- return CanExecute ((SolutionEntityItem)item, context, configuration);
- else if (item is WorkspaceItem)
- return CanExecute ((WorkspaceItem) item, context, configuration);
- else
- return GetNext (item).CanExecute (item, context, configuration);
- }
-
- protected virtual bool CanExecute (SolutionEntityItem item, ExecutionContext context, ConfigurationSelector configuration)
- {
- return GetNext (item).CanExecute ((IBuildTarget) item, context, configuration);
- }
-
- protected virtual bool CanExecute (Solution solution, ExecutionContext context, ConfigurationSelector configuration)
- {
- return GetNext (solution).CanExecute ((IBuildTarget) solution, context, configuration);
- }
-
- protected virtual bool CanExecute (WorkspaceItem item, ExecutionContext context, ConfigurationSelector configuration)
- {
- if (item is Solution)
- return CanExecute ((Solution) item, context, configuration);
- else
- return GetNext (item).CanExecute ((IBuildTarget) item, context, configuration);
- }
-
- public virtual IEnumerable<ExecutionTarget> GetExecutionTargets (IBuildTarget item, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem)
- return GetExecutionTargets ((SolutionEntityItem)item, configuration);
- else if (item is WorkspaceItem)
- return GetExecutionTargets ((WorkspaceItem) item, configuration);
- else
- return GetNext (item).GetExecutionTargets (item, configuration);
- }
-
- protected virtual IEnumerable<ExecutionTarget> GetExecutionTargets (SolutionEntityItem item, ConfigurationSelector configuration)
- {
- return GetNext (item).GetExecutionTargets ((IBuildTarget) item, configuration);
- }
-
- protected virtual IEnumerable<ExecutionTarget> GetExecutionTargets (Solution solution, ConfigurationSelector configuration)
- {
- return GetNext (solution).GetExecutionTargets ((IBuildTarget) solution, configuration);
- }
-
- protected virtual IEnumerable<ExecutionTarget> GetExecutionTargets (WorkspaceItem item, ConfigurationSelector configuration)
- {
- if (item is Solution)
- return GetExecutionTargets ((Solution) item, configuration);
- else
- return GetNext (item).GetExecutionTargets ((IBuildTarget) item, configuration);
- }
-
- public virtual bool GetNeedsBuilding (IBuildTarget item, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem)
- return GetNeedsBuilding ((SolutionEntityItem) item, configuration);
- if (item is WorkspaceItem)
- return GetNeedsBuilding ((WorkspaceItem) item, configuration);
- return GetNext (item).GetNeedsBuilding (item, configuration);
- }
-
- protected virtual bool GetNeedsBuilding (SolutionEntityItem item, ConfigurationSelector configuration)
- {
- return GetNext (item).GetNeedsBuilding ((IBuildTarget) item, configuration);
- }
-
- protected virtual bool GetNeedsBuilding (Solution item, ConfigurationSelector configuration)
- {
- return GetNext (item).GetNeedsBuilding ((IBuildTarget) item, configuration);
- }
-
- protected virtual bool GetNeedsBuilding (WorkspaceItem item, ConfigurationSelector configuration)
- {
- if (item is Solution)
- return GetNeedsBuilding ((Solution) item, configuration);
- return GetNext (item).GetNeedsBuilding ((IBuildTarget) item, configuration);
- }
-
- public virtual void SetNeedsBuilding (IBuildTarget item, bool val, ConfigurationSelector configuration)
- {
- if (item is SolutionEntityItem)
- SetNeedsBuilding ((SolutionEntityItem) item, val, configuration);
- else if (item is WorkspaceItem)
- SetNeedsBuilding ((WorkspaceItem) item, val, configuration);
- else
- GetNext (item).SetNeedsBuilding (item, val, configuration);
- }
-
- protected virtual void SetNeedsBuilding (SolutionEntityItem item, bool val, ConfigurationSelector configuration)
- {
- GetNext (item).SetNeedsBuilding ((IBuildTarget) item, val, configuration);
- }
-
- protected virtual void SetNeedsBuilding (Solution item, bool val, ConfigurationSelector configuration)
- {
- GetNext (item).SetNeedsBuilding ((IBuildTarget) item, val, configuration);
- }
-
- protected virtual void SetNeedsBuilding (WorkspaceItem item, bool val, ConfigurationSelector configuration)
- {
- if (item is Solution)
- SetNeedsBuilding ((Solution) item, val, configuration);
- else
- GetNext (item).SetNeedsBuilding ((IBuildTarget) item, val, configuration);
- }
-
- internal virtual BuildResult Compile (IProgressMonitor monitor, SolutionEntityItem item, BuildData buildData, ItemCompileCallback callback)
- {
- compileCallbackStack.Push (callback);
- try {
- BuildResult res = Compile (monitor, item, buildData);
- return res;
- } finally {
- compileCallbackStack.Pop ();
- }
- }
-
- protected virtual BuildResult Compile (IProgressMonitor monitor, SolutionEntityItem item, BuildData buildData)
- {
- return GetNext (item).Compile (monitor, item, buildData, compileCallbackStack.Peek ());
- }
-
- public virtual IEnumerable<string> GetReferencedAssemblies (DotNetProject project, ConfigurationSelector configuration, bool includeProjectReferences)
- {
- return GetNext (project).GetReferencedAssemblies (project, configuration, includeProjectReferences);
- }
}
public class BuildData
@@ -405,16 +92,21 @@ namespace MonoDevelop.Projects
public ConfigurationSelector ConfigurationSelector { get; internal set; }
}
- class UnknownItem: IBuildTarget
+ class UnknownItem: WorkspaceObject, IBuildTarget
{
public static UnknownItem Instance = new UnknownItem ();
-
- public BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
+
+ public Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector configuration, bool buildReferencedTargets = false)
{
- return new BuildResult ();
+ return Task.FromResult (BuildResult.Success);
}
- public void Execute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ public Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Task.FromResult (BuildResult.Success);
+ }
+
+ public Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
throw new System.NotImplementedException();
}
@@ -424,45 +116,24 @@ namespace MonoDevelop.Projects
return false;
}
- public bool SupportsTarget (string target)
- {
- return false;
- }
-
public bool NeedsBuilding (ConfigurationSelector configuration)
{
return false;
}
-
- public void SetNeedsBuilding (bool needsBuilding, ConfigurationSelector configuration)
+
+ protected override string OnGetName ()
{
+ return "Unknown";
}
-
- public void Save (IProgressMonitor monitor)
+
+ protected override string OnGetBaseDirectory ()
{
+ return FilePath.Empty;
}
-
- public string Name {
- get { return "Unknown"; }
- set { }
- }
-
-
- public FilePath ItemDirectory {
- get { return FilePath.Empty; }
- }
-
- public FilePath BaseDirectory {
- get { return FilePath.Empty; }
- set { }
- }
-
- public void Dispose ()
+
+ protected override string OnGetItemDirectory ()
{
- }
-
- public System.Collections.IDictionary ExtendedProperties {
- get { return null; }
+ return FilePath.Empty;
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectBinding.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterDotNetProject.cs
index ca7f7527a1..1d237ac31f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.SharedAssetsProjects/SharedAssetsProjectBinding.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterDotNetProject.cs
@@ -1,5 +1,5 @@
//
-// SharedAssetsProjectBinding.cs
+// RegisterDotNetProject.cs
//
// Author:
// Lluis Sanchez Gual <lluis@xamarin.com>
@@ -24,35 +24,22 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
+using Mono.Addins;
-namespace MonoDevelop.Projects.SharedAssetsProjects
+namespace MonoDevelop.Projects
{
- public class SharedAssetsProjectBinding: IProjectBinding
+ public class RegisterDotNetProjectTypeAttribute: RegisterProjectTypeAttribute
{
- #region IProjectBinding implementation
-
- public Project CreateProject (ProjectCreateInformation info, System.Xml.XmlElement projectOptions)
- {
- return new SharedAssetsProject (info, projectOptions);
- }
-
- public Project CreateSingleFileProject (string sourceFile)
+ protected RegisterDotNetProjectTypeAttribute ()
{
- throw new NotImplementedException ();
}
- public bool CanCreateSingleFileProject (string sourceFile)
+ public RegisterDotNetProjectTypeAttribute ([NodeAttribute ("guid")] string guid, [NodeAttribute("language")] string language): base (guid)
{
- return false;
- }
-
- public string Name {
- get {
- return "SharedAssetsProject";
- }
}
- #endregion
+ [NodeAttribute ("language", Required=true)]
+ public string Language { get; set; }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectAttribute.cs
index adb9f0a0c4..e582055a24 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildExtension.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectAttribute.cs
@@ -1,5 +1,5 @@
//
-// MSBuildExtension.cs
+// MSBuildProjectTypeAttribute.cs
//
// Author:
// Lluis Sanchez Gual <lluis@xamarin.com>
@@ -25,24 +25,20 @@
// THE SOFTWARE.
using System;
using MonoDevelop.Core;
+using System.Threading.Tasks;
+using MonoDevelop.Projects.Formats.MSBuild;
+using Mono.Addins;
-namespace MonoDevelop.Projects.Formats.MSBuild
+namespace MonoDevelop.Projects
{
- public class MSBuildExtension
+ public class RegisterProjectTypeAttribute: RegisterSolutionItemTypeAttribute
{
- public MSBuildProjectHandler Handler { get; set; }
-
- public virtual void LoadProject (IProgressMonitor monitor, SolutionEntityItem item, MSBuildProject project)
- {
- }
-
- public virtual void SaveProject (IProgressMonitor monitor, SolutionEntityItem item, MSBuildProject project)
+ protected RegisterProjectTypeAttribute ()
{
}
- public virtual object GetService (Type t)
+ public RegisterProjectTypeAttribute ([NodeAttribute ("guid")] string guid): base (guid)
{
- return null;
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectFlavorAttribute.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectFlavorAttribute.cs
new file mode 100644
index 0000000000..023723f1db
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectFlavorAttribute.cs
@@ -0,0 +1,48 @@
+//
+// ProjectFlavorTypeAttribute.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Linq;
+using Mono.Addins;
+
+namespace MonoDevelop.Projects
+{
+ public class RegisterProjectFlavorAttribute: RegisterProjectModelExtensionAttribute
+ {
+ internal RegisterProjectFlavorAttribute ()
+ {
+ }
+
+ public RegisterProjectFlavorAttribute ([NodeAttribute ("guid")] string guid)
+ {
+ Guid = guid;
+ }
+
+ [NodeAttribute ("guid", Description = "GUID of the extension. The extension will be loaded if the project has this GUID in the project type GUID list. " +
+ "If not specified, the extension will be applied to all projects.")]
+ public string Guid { get; set; }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectModelExtensionAttribute.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectModelExtensionAttribute.cs
new file mode 100644
index 0000000000..9c47679650
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterProjectModelExtensionAttribute.cs
@@ -0,0 +1,36 @@
+//
+// RegisterProjectModelExtensionAttribute.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using Mono.Addins;
+
+namespace MonoDevelop.Projects
+{
+ public class RegisterProjectModelExtensionAttribute: CustomExtensionAttribute
+ {
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterSolutionItemTypeAttribute.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterSolutionItemTypeAttribute.cs
new file mode 100644
index 0000000000..ccdc33ab8b
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RegisterSolutionItemTypeAttribute.cs
@@ -0,0 +1,62 @@
+//
+// SolutionItemTypeAttribute.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Threading.Tasks;
+using MonoDevelop.Core;
+using Mono.Addins;
+using MonoDevelop.Core.ProgressMonitoring;
+
+namespace MonoDevelop.Projects
+{
+ public class RegisterSolutionItemTypeAttribute: CustomExtensionAttribute
+ {
+ [NodeAttribute ("guid", Required=true)]
+ public string Guid { get; set; }
+
+ [NodeAttribute ("extension")]
+ public string Extension { get; set; }
+
+ [NodeAttribute ("import")]
+ public string Import { get; set; }
+
+ [NodeAttribute ("alias")]
+ public string Alias { get; set; }
+
+ public string TypeName {
+ get { return ((TypeExtensionNode)ExtensionNode).TypeName; }
+ }
+
+ protected RegisterSolutionItemTypeAttribute ()
+ {
+ }
+
+ public RegisterSolutionItemTypeAttribute ([NodeAttribute ("guid")] string guid)
+ {
+ Guid = guid;
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs
index f0b7f171f2..97534bbc16 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs
@@ -36,18 +36,21 @@ using MonoDevelop.Core;
using MonoDevelop.Core.ProgressMonitoring;
using MonoDevelop.Core.StringParsing;
using MonoDevelop.Projects.Policies;
+using MonoDevelop.Core.Execution;
+using System.Threading.Tasks;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
[ProjectModelDataItem]
- public class Solution: WorkspaceItem, IConfigurationTarget, IPolicyProvider
+ public class Solution: WorkspaceItem, IConfigurationTarget, IPolicyProvider, IBuildTarget
{
internal object MemoryProbe = Counters.SolutionsInMemory.CreateMemoryProbe ();
SolutionFolder rootFolder;
string defaultConfiguration;
- SolutionEntityItem startupItem;
- List<SolutionEntityItem> startupItems;
+ SolutionItem startupItem;
+ List<SolutionItem> startupItems;
bool singleStartup = true;
// Used for serialization only
@@ -70,8 +73,24 @@ namespace MonoDevelop.Projects
{
Counters.SolutionsLoaded++;
configurations = new SolutionConfigurationCollection (this);
+ Initialize (this);
}
-
+
+ internal HashSet<string> LoadedProjects {
+ get;
+ set;
+ }
+
+ SolutionExtension itemExtension;
+
+ SolutionExtension SolutionExtension {
+ get {
+ if (itemExtension == null)
+ itemExtension = ExtensionChain.GetExtension<SolutionExtension> ();
+ return itemExtension;
+ }
+ }
+
public SolutionFolder RootFolder {
get {
if (rootFolder == null) {
@@ -103,18 +122,13 @@ namespace MonoDevelop.Projects
// Does not include solution folders
public ReadOnlyCollection<SolutionItem> Items {
get {
- if (solutionItems == null) {
- List<SolutionItem> list = new List<SolutionItem> ();
- foreach (SolutionItem item in GetAllSolutionItems ())
- if (!(item is SolutionFolder))
- list.Add (item);
- solutionItems = list.AsReadOnly ();
- }
+ if (solutionItems == null)
+ solutionItems = GetAllSolutionItems ().ToList().AsReadOnly ();
return solutionItems;
}
}
- public SolutionEntityItem StartupItem {
+ public SolutionItem StartupItem {
get {
if (startItemFileName != null) {
startupItem = FindSolutionItem (startItemFileName);
@@ -122,8 +136,8 @@ namespace MonoDevelop.Projects
singleStartup = true;
}
if (startupItem == null && singleStartup) {
- ReadOnlyCollection<SolutionEntityItem> its = GetAllSolutionItems<SolutionEntityItem> ();
- if (its.Count > 0)
+ var its = GetAllItems<SolutionItem> ();
+ if (its.Any ())
startupItem = its.FirstOrDefault (it => it.SupportsExecute ());
}
return startupItem;
@@ -161,12 +175,12 @@ namespace MonoDevelop.Projects
}
}
- public List<SolutionEntityItem> MultiStartupItems {
+ public List<SolutionItem> MultiStartupItems {
get {
if (multiStartupItems != null) {
- startupItems = new List<SolutionEntityItem> ();
+ startupItems = new List<SolutionItem> ();
foreach (string file in multiStartupItems) {
- SolutionEntityItem it = FindSolutionItem (file);
+ SolutionItem it = FindSolutionItem (file);
if (it != null)
startupItems.Add (it);
}
@@ -174,7 +188,7 @@ namespace MonoDevelop.Projects
singleStartup = false;
}
else if (startupItems == null)
- startupItems = new List<SolutionEntityItem> ();
+ startupItems = new List<SolutionItem> ();
return startupItems;
}
}
@@ -200,7 +214,7 @@ namespace MonoDevelop.Projects
if (multiStartupItems != null)
return multiStartupItems;
List<string> files = new List<string> ();
- foreach (SolutionEntityItem item in MultiStartupItems)
+ foreach (SolutionItem item in MultiStartupItems)
files.Add (item.FileName);
return files;
}
@@ -248,30 +262,30 @@ namespace MonoDevelop.Projects
CleanItemProperties (UserProperties, RootFolder, "MonoDevelop.Ide.ItemProperties");
}
- void CollectItemProperties (PropertyBag props, SolutionItem item, string path)
+ void CollectItemProperties (PropertyBag props, SolutionFolderItem item, string path)
{
if (!item.UserProperties.IsEmpty && item.ParentFolder != null)
props.SetValue (path, item.UserProperties);
SolutionFolder sf = item as SolutionFolder;
if (sf != null) {
- foreach (SolutionItem ci in sf.Items)
+ foreach (SolutionFolderItem ci in sf.Items)
CollectItemProperties (props, ci, path + "." + ci.Name);
}
}
- void CleanItemProperties (PropertyBag props, SolutionItem item, string path)
+ void CleanItemProperties (PropertyBag props, SolutionFolderItem item, string path)
{
props.RemoveValue (path);
SolutionFolder sf = item as SolutionFolder;
if (sf != null) {
- foreach (SolutionItem ci in sf.Items)
+ foreach (SolutionFolderItem ci in sf.Items)
CleanItemProperties (props, ci, path + "." + ci.Name);
}
}
- void LoadItemProperties (PropertyBag props, SolutionItem item, string path)
+ void LoadItemProperties (PropertyBag props, SolutionFolderItem item, string path)
{
PropertyBag info = props.GetValue<PropertyBag> (path);
if (info != null) {
@@ -281,14 +295,14 @@ namespace MonoDevelop.Projects
SolutionFolder sf = item as SolutionFolder;
if (sf != null) {
- foreach (SolutionItem ci in sf.Items)
+ foreach (SolutionFolderItem ci in sf.Items)
LoadItemProperties (props, ci, path + "." + ci.Name);
}
}
public void CreateDefaultConfigurations ()
{
- foreach (SolutionEntityItem item in Items.Where (it => it.SupportsBuild ())) {
+ foreach (SolutionItem item in Items.Where (it => it.SupportsBuild ())) {
foreach (ItemConfiguration conf in item.Configurations) {
SolutionConfiguration sc = Configurations [conf.Id];
if (sc == null) {
@@ -308,7 +322,7 @@ namespace MonoDevelop.Projects
public SolutionConfiguration AddConfiguration (string name, bool createConfigForItems)
{
SolutionConfiguration conf = new SolutionConfiguration (name);
- foreach (SolutionEntityItem item in Items.Where (it => it.SupportsBuild())) {
+ foreach (SolutionItem item in Items.Where (it => it.SupportsBuild())) {
if (createConfigForItems && item.GetConfiguration (new ItemConfigurationSelector (name)) == null) {
SolutionItemConfiguration newc = item.CreateConfiguration (name);
if (item.DefaultConfiguration != null)
@@ -334,15 +348,15 @@ namespace MonoDevelop.Projects
return (SolutionConfiguration) configuration.GetConfiguration (this) ?? DefaultConfiguration;
}
- public SolutionItem GetSolutionItem (string itemId)
+ public SolutionFolderItem GetSolutionItem (string itemId)
{
- foreach (SolutionItem item in Items)
+ foreach (SolutionFolderItem item in Items)
if (item.ItemId == itemId)
return item;
return null;
}
- public override SolutionEntityItem FindSolutionItem (string fileName)
+ public SolutionItem FindSolutionItem (string fileName)
{
return RootFolder.FindSolutionItem (fileName);
}
@@ -352,11 +366,16 @@ namespace MonoDevelop.Projects
return RootFolder.FindProjectByName (name);
}
- public override ReadOnlyCollection<T> GetAllSolutionItems<T> ()
+ public IEnumerable<SolutionItem> GetAllSolutionItems ()
{
- return RootFolder.GetAllItems<T> ();
+ return GetAllItems<SolutionItem> ();
}
-
+
+ public IEnumerable<Project> GetAllProjects ()
+ {
+ return GetAllItems<Project> ();
+ }
+
public ReadOnlyCollection<T> GetAllSolutionItemsWithTopologicalSort<T> (ConfigurationSelector configuration) where T: SolutionItem
{
return RootFolder.GetAllItemsWithTopologicalSort<T> (configuration);
@@ -378,17 +397,22 @@ namespace MonoDevelop.Projects
return RootFolder.GetProjectsContainingFile (fileName);
}
- public override bool ContainsItem (IWorkspaceObject obj)
+ public override bool ContainsItem (WorkspaceObject obj)
{
if (base.ContainsItem (obj))
return true;
- foreach (SolutionItem it in GetAllSolutionItems<SolutionItem> ()) {
+ foreach (SolutionFolderItem it in GetAllItems<SolutionFolderItem> ()) {
if (it == obj)
return true;
}
return false;
}
+
+ protected override IEnumerable<WorkspaceObject> OnGetChildren ()
+ {
+ yield return RootFolder;
+ }
public string Description {
get {
@@ -494,7 +518,7 @@ namespace MonoDevelop.Projects
}
set {
version = value;
- foreach (SolutionEntityItem item in GetAllSolutionItems<SolutionEntityItem> ()) {
+ foreach (SolutionItem item in GetAllItems<SolutionItem> ()) {
if (item.SyncVersionWithSolution)
item.Version = value;
}
@@ -515,7 +539,7 @@ namespace MonoDevelop.Projects
return list == null || !list.Contains (solutionItemPath);
}
- public void SetSolutionItemEnabled (string solutionItemPath, bool enabled)
+ internal void SetSolutionItemEnabled (string solutionItemPath, bool enabled)
{
solutionItemPath = GetRelativeChildPath (Path.GetFullPath (solutionItemPath));
var list = UserProperties.GetValue<List<string>> ("DisabledProjects");
@@ -543,25 +567,91 @@ namespace MonoDevelop.Projects
}
}
}
-
- protected override BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+
+
+ public Task<BuildResult> Clean (ProgressMonitor monitor, string configuration)
+ {
+ return Clean (monitor, (SolutionConfigurationSelector) configuration);
+ }
+
+ public Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return SolutionExtension.Clean (monitor, configuration);
+ }
+
+ public Task<BuildResult> Build (ProgressMonitor monitor, string configuration)
+ {
+ return SolutionExtension.Build (monitor, (SolutionConfigurationSelector) configuration);
+ }
+
+ Task<BuildResult> IBuildTarget.Build (ProgressMonitor monitor, ConfigurationSelector configuration, bool buildReferencedTargets)
+ {
+ return Build (monitor, configuration);
+ }
+
+ public Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return SolutionExtension.Build (monitor, configuration);
+ }
+
+ public bool NeedsBuilding (ConfigurationSelector configuration)
+ {
+ return SolutionExtension.NeedsBuilding (configuration);
+ }
+
+ public Task Execute (ProgressMonitor monitor, ExecutionContext context, string configuration)
+ {
+ return Execute (monitor, context, (SolutionConfigurationSelector) configuration);
+ }
+
+ public Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return SolutionExtension.Execute (monitor, context, configuration);
+ }
+
+ public bool CanExecute (ExecutionContext context, string configuration)
+ {
+ return CanExecute (context, (SolutionConfigurationSelector) configuration);
+ }
+
+ public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return SolutionExtension.CanExecute (context, configuration);
+ }
+
+ public IEnumerable<ExecutionTarget> GetExecutionTargets (string configuration)
+ {
+ return GetExecutionTargets ((SolutionConfigurationSelector) configuration);
+ }
+
+ public IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration)
+ {
+ return SolutionExtension.GetExecutionTargets (this, configuration);
+ }
+
+ protected virtual Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
{
return RootFolder.Build (monitor, configuration);
}
-
- protected override void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration)
+
+ protected virtual bool OnGetNeedsBuilding (ConfigurationSelector configuration)
+ {
+ return RootFolder.NeedsBuilding (configuration);
+ }
+
+ protected virtual Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
{
- RootFolder.Clean (monitor, configuration);
+ return RootFolder.Clean (monitor, configuration);
}
- protected internal override bool OnGetCanExecute(ExecutionContext context, ConfigurationSelector configuration)
+ protected virtual bool OnGetCanExecute(ExecutionContext context, ConfigurationSelector configuration)
{
if (SingleStartup) {
if (StartupItem == null)
return false;
return StartupItem.CanExecute (context, configuration);
} else {
- foreach (SolutionEntityItem it in MultiStartupItems) {
+ foreach (SolutionItem it in MultiStartupItems) {
if (it.CanExecute (context, configuration))
return true;
}
@@ -569,44 +659,36 @@ namespace MonoDevelop.Projects
}
}
- protected internal override void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ protected async virtual Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
if (SingleStartup) {
if (StartupItem == null) {
monitor.ReportError (GettextCatalog.GetString ("Startup item not set"), null);
return;
}
- StartupItem.Execute (monitor, context, configuration);
+ await StartupItem.Execute (monitor, context, configuration);
} else {
- List<IAsyncOperation> list = new List<IAsyncOperation> ();
+ var tasks = new List<Task> ();
+ var monitors = new List<AggregatedProgressMonitor> ();
monitor.BeginTask ("Executing projects", 1);
- SynchronizedProgressMonitor syncMonitor = new SynchronizedProgressMonitor (monitor);
-
- foreach (SolutionEntityItem it in MultiStartupItems) {
+ foreach (SolutionItem it in MultiStartupItems) {
if (!it.CanExecute (context, configuration))
continue;
AggregatedProgressMonitor mon = new AggregatedProgressMonitor ();
- mon.AddSlaveMonitor (syncMonitor, MonitorAction.ReportError | MonitorAction.ReportWarning | MonitorAction.SlaveCancel);
- list.Add (mon.AsyncOperation);
- SolutionEntityItem cit = it;
-
- Thread t = new Thread (delegate () {
- try {
- using (mon) {
- cit.Execute (mon, context, configuration);
- }
- } catch (Exception ex) {
- LoggingService.LogError ("Project execution failed", ex);
- }
- });
- t.Name = "Project execution";
- t.IsBackground = true;
- t.Start ();
+ mon.AddSlaveMonitor (monitor, MonitorAction.ReportError | MonitorAction.ReportWarning | MonitorAction.SlaveCancel);
+ monitors.Add (mon);
+ tasks.Add (it.Execute (mon, context, configuration));
}
- foreach (IAsyncOperation op in list)
- op.WaitForCompleted ();
-
+ try {
+ await Task.WhenAll (tasks);
+ } catch (Exception ex) {
+ LoggingService.LogError ("Project execution failed", ex);
+ } finally {
+ foreach (var m in monitors)
+ m.Dispose ();
+ }
+
monitor.EndTask ();
}
}
@@ -617,25 +699,25 @@ namespace MonoDevelop.Projects
StartupItemChanged (this, e);
}
- public override void ConvertToFormat (FileFormat format, bool convertChildren)
+ public async override Task ConvertToFormat (FileFormat format, bool convertChildren)
{
- base.ConvertToFormat (format, convertChildren);
- foreach (SolutionItem item in GetAllSolutionItems<SolutionItem> ())
- ConvertToSolutionFormat (item, convertChildren);
+ await base.ConvertToFormat (format, convertChildren);
+ foreach (SolutionFolderItem item in GetAllItems<SolutionFolderItem> ())
+ await ConvertToSolutionFormat (item, convertChildren);
}
public override bool SupportsFormat (FileFormat format)
{
if (!base.SupportsFormat (format))
return false;
- return GetAllSolutionItems<SolutionEntityItem> ().All (p => p.SupportsFormat (format));
+ return GetAllItems<SolutionItem> ().All (p => p.SupportsFormat (format));
}
- public override List<FilePath> GetItemFiles (bool includeReferencedFiles)
+ protected override IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
{
- List<FilePath> files = base.GetItemFiles (includeReferencedFiles);
+ List<FilePath> files = base.OnGetItemFiles (includeReferencedFiles).ToList ();
if (includeReferencedFiles) {
- foreach (SolutionEntityItem item in GetAllSolutionItems<SolutionEntityItem> ())
+ foreach (SolutionItem item in GetAllItems<SolutionItem> ())
files.AddRange (item.GetItemFiles (true));
}
return files;
@@ -649,7 +731,7 @@ namespace MonoDevelop.Projects
SolutionFolder sf = args.SolutionItem as SolutionFolder;
if (sf != null) {
- foreach (SolutionItem eitem in sf.GetAllItems<SolutionItem> ())
+ foreach (SolutionFolderItem eitem in sf.GetAllItems<SolutionFolderItem> ())
SetupNewItem (eitem, null);
}
else {
@@ -660,14 +742,14 @@ namespace MonoDevelop.Projects
SolutionItemAdded (this, args);
}
- void SetupNewItem (SolutionItem item, SolutionItem replacedItem)
+ void SetupNewItem (SolutionFolderItem item, SolutionFolderItem replacedItem)
{
- ConvertToSolutionFormat (item, false);
+ ConvertToSolutionFormat (item, false).Wait ();
- SolutionEntityItem eitem = item as SolutionEntityItem;
+ SolutionItem eitem = item as SolutionItem;
if (eitem != null) {
eitem.NeedsReload = false;
- if (eitem.SupportsBuild () || replacedItem != null) {
+ if (eitem.SupportsConfigurations () || replacedItem != null) {
if (replacedItem == null) {
// Register the new entry in every solution configuration
foreach (SolutionConfiguration conf in Configurations)
@@ -678,11 +760,11 @@ namespace MonoDevelop.Projects
} else {
// Reuse the configuration information of the replaced item
foreach (SolutionConfiguration conf in Configurations)
- conf.ReplaceItem ((SolutionEntityItem)replacedItem, eitem);
+ conf.ReplaceItem ((SolutionItem)replacedItem, eitem);
if (StartupItem == replacedItem)
StartupItem = eitem;
else {
- int i = MultiStartupItems.IndexOf ((SolutionEntityItem)replacedItem);
+ int i = MultiStartupItems.IndexOf ((SolutionItem)replacedItem);
if (i != -1)
MultiStartupItems [i] = eitem;
}
@@ -691,11 +773,11 @@ namespace MonoDevelop.Projects
}
}
- void ConvertToSolutionFormat (SolutionItem item, bool force)
+ async Task ConvertToSolutionFormat (SolutionFolderItem item, bool force)
{
- SolutionEntityItem eitem = item as SolutionEntityItem;
+ SolutionItem eitem = item as SolutionItem;
if (force || !FileFormat.Format.SupportsMixedFormats || eitem == null || !eitem.IsSaved) {
- this.FileFormat.Format.ConvertToFormat (item);
+ await this.FileFormat.Format.ConvertToFormat (item);
if (eitem != null)
eitem.InstallFormat (this.FileFormat);
}
@@ -707,11 +789,11 @@ namespace MonoDevelop.Projects
SolutionFolder sf = args.SolutionItem as SolutionFolder;
if (sf != null) {
- foreach (SolutionEntityItem eitem in sf.GetAllItems<SolutionEntityItem> ())
+ foreach (SolutionItem eitem in sf.GetAllItems<SolutionItem> ())
DetachItem (eitem, args.Reloading);
}
else {
- SolutionEntityItem item = args.SolutionItem as SolutionEntityItem;
+ SolutionItem item = args.SolutionItem as SolutionItem;
if (item != null)
DetachItem (item, args.Reloading);
}
@@ -720,7 +802,7 @@ namespace MonoDevelop.Projects
SolutionItemRemoved (this, args);
}
- void DetachItem (SolutionEntityItem item, bool reloading)
+ void DetachItem (SolutionItem item, bool reloading)
{
item.NeedsReload = false;
if (!reloading) {
@@ -744,7 +826,7 @@ namespace MonoDevelop.Projects
if (projectToRemove == null)
return;
- foreach (DotNetProject project in GetAllSolutionItems <DotNetProject>()) {
+ foreach (DotNetProject project in GetAllItems <DotNetProject>()) {
if (project == projectToRemove)
continue;
@@ -760,7 +842,27 @@ namespace MonoDevelop.Projects
}
}
}
+
+ internal void ReadSolution (ProgressMonitor monitor, SlnFile file)
+ {
+ SolutionExtension.OnReadSolution (monitor, file);
+ }
+
+ protected virtual void OnReadSolution (ProgressMonitor monitor, SlnFile file)
+ {
+ ((MSBuildFileFormat)FileFormat.Format).SlnFileFormat.LoadSolution (this, file, monitor);
+ }
+
+ internal void WriteSolution (ProgressMonitor monitor, SlnFile file)
+ {
+ SolutionExtension.OnWriteSolution (monitor, file);
+ }
+ protected virtual void OnWriteSolution (ProgressMonitor monitor, SlnFile file)
+ {
+ ((MSBuildFileFormat)FileFormat.Format).SlnFileFormat.WriteFileInternal (file, this, monitor);
+ }
+
internal void NotifyConfigurationsChanged ()
{
OnConfigurationsChanged ();
@@ -843,6 +945,54 @@ namespace MonoDevelop.Projects
public event SolutionItemModifiedEventHandler EntryModified;
public event SolutionItemEventHandler EntrySaved;
public event EventHandler<SolutionItemEventArgs> ItemReloadRequired;
+
+ protected override IEnumerable<WorkspaceObjectExtension> CreateDefaultExtensions ()
+ {
+ return base.CreateDefaultExtensions ().Concat (Enumerable.Repeat (new DefaultSolutionExtension (), 1));
+ }
+
+ internal class DefaultSolutionExtension: SolutionExtension
+ {
+ internal protected override IEnumerable<FilePath> GetItemFiles (bool includeReferencedFiles)
+ {
+ return Solution.OnGetItemFiles (includeReferencedFiles);
+ }
+
+ internal protected override Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Solution.OnBuild (monitor, configuration);
+ }
+
+ internal protected override bool NeedsBuilding (ConfigurationSelector configuration)
+ {
+ return Solution.OnGetNeedsBuilding (configuration);
+ }
+
+ internal protected override Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Solution.OnClean (monitor, configuration);
+ }
+
+ internal protected override Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return Solution.OnExecute (monitor, context, configuration);
+ }
+
+ internal protected override bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return Solution.OnGetCanExecute (context, configuration);
+ }
+
+ internal protected override void OnReadSolution (ProgressMonitor monitor, SlnFile file)
+ {
+ Solution.OnReadSolution (monitor, file);
+ }
+
+ internal protected override void OnWriteSolution (ProgressMonitor monitor, SlnFile file)
+ {
+ Solution.OnWriteSolution (monitor, file);
+ }
+ }
}
[Mono.Addins.Extension]
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfiguration.cs
index dfa4bc6832..717edf5f9b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfiguration.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfiguration.cs
@@ -73,7 +73,7 @@ namespace MonoDevelop.Projects
get { return configurations.AsReadOnly (); }
}
- public bool BuildEnabledForItem (SolutionEntityItem item)
+ public bool BuildEnabledForItem (SolutionItem item)
{
foreach (SolutionConfigurationEntry entry in configurations) {
if (entry.Item == item)
@@ -82,7 +82,7 @@ namespace MonoDevelop.Projects
return false;
}
- public string GetMappedConfiguration (SolutionEntityItem item)
+ public string GetMappedConfiguration (SolutionItem item)
{
foreach (SolutionConfigurationEntry entry in configurations) {
if (entry.Item == item)
@@ -91,7 +91,7 @@ namespace MonoDevelop.Projects
return null;
}
- public SolutionConfigurationEntry GetEntryForItem (SolutionEntityItem item)
+ public SolutionConfigurationEntry GetEntryForItem (SolutionItem item)
{
foreach (SolutionConfigurationEntry entry in configurations) {
if (entry.Item == item)
@@ -100,13 +100,13 @@ namespace MonoDevelop.Projects
return null;
}
- public SolutionConfigurationEntry AddItem (SolutionEntityItem item)
+ public SolutionConfigurationEntry AddItem (SolutionItem item)
{
string conf = FindMatchingConfiguration (item);
return AddItem (item, conf != null, conf);
}
- string FindMatchingConfiguration (SolutionEntityItem item)
+ string FindMatchingConfiguration (SolutionItem item)
{
SolutionItemConfiguration startupConfiguration = null;
@@ -153,7 +153,7 @@ namespace MonoDevelop.Projects
return item.Configurations [0].Id;
}
- public SolutionConfigurationEntry AddItem (SolutionEntityItem item, bool build, string itemConfiguration)
+ public SolutionConfigurationEntry AddItem (SolutionItem item, bool build, string itemConfiguration)
{
if (itemConfiguration == null)
itemConfiguration = Name;
@@ -166,7 +166,7 @@ namespace MonoDevelop.Projects
return conf;
}
- public void RemoveItem (SolutionEntityItem item)
+ public void RemoveItem (SolutionItem item)
{
for (int n=0; n<configurations.Count; n++) {
if (configurations [n].Item == item) {
@@ -176,7 +176,7 @@ namespace MonoDevelop.Projects
}
}
- internal void ReplaceItem (SolutionEntityItem oldItem, SolutionEntityItem newItem)
+ internal void ReplaceItem (SolutionItem oldItem, SolutionItem newItem)
{
foreach (var e in configurations.Where (ce => ce.Item == oldItem))
e.Item = newItem;
@@ -203,7 +203,7 @@ namespace MonoDevelop.Projects
public class SolutionConfigurationEntry
{
- SolutionEntityItem item;
+ SolutionItem item;
SolutionConfiguration parentConfig;
[ItemProperty ("name")]
@@ -227,7 +227,7 @@ namespace MonoDevelop.Projects
this.deploy = other.deploy;
}
- internal SolutionConfigurationEntry (SolutionConfiguration parentConfig, SolutionEntityItem item)
+ internal SolutionConfigurationEntry (SolutionConfiguration parentConfig, SolutionItem item)
{
this.parentConfig = parentConfig;
this.item = item;
@@ -258,12 +258,12 @@ namespace MonoDevelop.Projects
set { deploy = value; }
}
- public SolutionEntityItem Item {
+ public SolutionItem Item {
get {
if (item == null && parentConfig != null) {
Solution sol = parentConfig.ParentSolution;
if (sol != null)
- item = sol.GetSolutionItem (itemId) as SolutionEntityItem;
+ item = sol.GetSolutionItem (itemId) as SolutionItem;
}
return item;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfigurationSelector.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfigurationSelector.cs
index 04beb91589..531bd74947 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfigurationSelector.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionConfigurationSelector.cs
@@ -48,9 +48,9 @@ namespace MonoDevelop.Projects
public override ItemConfiguration GetConfiguration (IConfigurationTarget target)
{
ItemConfiguration sconf;
- if (target is SolutionEntityItem) {
+ if (target is SolutionItem) {
// Get the mapped configuration
- SolutionEntityItem item = (SolutionEntityItem) target;
+ SolutionItem item = (SolutionItem) target;
if (item.ParentSolution != null) {
SolutionConfiguration config = item.ParentSolution.Configurations [Id];
if (config != null) {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionEntityItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionEntityItem.cs
deleted file mode 100644
index 0698a3fcf3..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionEntityItem.cs
+++ /dev/null
@@ -1,584 +0,0 @@
-// SolutionEntityItem.cs
-//
-// Author:
-// Lluis Sanchez Gual <lluis@novell.com>
-//
-// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-//
-
-using System;
-using System.Linq;
-using System.Xml;
-using System.IO;
-using System.Collections;
-using System.Collections.ObjectModel;
-using System.Collections.Specialized;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Diagnostics;
-using System.CodeDom.Compiler;
-
-using MonoDevelop.Core;
-using MonoDevelop.Projects;
-using MonoDevelop.Core.Serialization;
-using MonoDevelop.Projects.Extensions;
-using MonoDevelop.Core.StringParsing;
-
-namespace MonoDevelop.Projects
-{
- [ProjectModelDataItem (FallbackType = typeof(UnknownSolutionItem))]
- public abstract class SolutionEntityItem : SolutionItem, IConfigurationTarget, IWorkspaceFileObject
- {
- internal object MemoryProbe = Counters.ItemsInMemory.CreateMemoryProbe ();
-
- ProjectItemCollection items;
- ProjectItemCollection wildcardItems;
- ItemCollection<SolutionEntityItem> dependencies = new ItemCollection<SolutionEntityItem> ();
-
- SolutionItemEventArgs thisItemArgs;
-
- FileStatusTracker<SolutionItemEventArgs> fileStatusTracker;
-
- FilePath fileName;
- string name;
-
- FileFormat fileFormat;
-
- SolutionItemConfiguration activeConfiguration;
- SolutionItemConfigurationCollection configurations;
-
- public event EventHandler ConfigurationsChanged;
- public event ConfigurationEventHandler DefaultConfigurationChanged;
- public event ConfigurationEventHandler ConfigurationAdded;
- public event ConfigurationEventHandler ConfigurationRemoved;
- public event EventHandler<ProjectItemEventArgs> ProjectItemAdded;
- public event EventHandler<ProjectItemEventArgs> ProjectItemRemoved;
-
- public SolutionEntityItem ()
- {
- items = new ProjectItemCollection (this);
- wildcardItems = new ProjectItemCollection (this);
- thisItemArgs = new SolutionItemEventArgs (this);
- configurations = new SolutionItemConfigurationCollection (this);
- configurations.ConfigurationAdded += new ConfigurationEventHandler (OnConfigurationAddedToCollection);
- configurations.ConfigurationRemoved += new ConfigurationEventHandler (OnConfigurationRemovedFromCollection);
- Counters.ItemsLoaded++;
- fileStatusTracker = new FileStatusTracker<SolutionItemEventArgs> (this, OnReloadRequired, new SolutionItemEventArgs (this));
- }
-
- public override void Dispose ()
- {
- if (Disposed)
- return;
-
- Counters.ItemsLoaded--;
-
- foreach (var item in items.Concat (wildcardItems)) {
- IDisposable disp = item as IDisposable;
- if (disp != null)
- disp.Dispose ();
- }
-
- // items = null;
- // wildcardItems = null;
- // thisItemArgs = null;
- // fileStatusTracker = null;
- // fileFormat = null;
- // activeConfiguration = null;
- // configurations = null;
-
- base.Dispose ();
- }
-
-
- internal override void SetItemHandler (ISolutionItemHandler handler)
- {
- string oldName = Name;
- string oldFile = FileName;
-
- base.SetItemHandler (handler);
-
- // This will update the name if needed, when SyncFileName is true
- Name = oldName;
- if (!string.IsNullOrEmpty (oldFile))
- FileName = oldFile;
- }
-
- [ItemProperty ("ReleaseVersion", DefaultValue="0.1")]
- string releaseVersion = "0.1";
-
- [ItemProperty ("SynchReleaseVersion", DefaultValue = true)]
- bool syncReleaseVersion = true;
-
- public string Version {
- get {
- // If syncReleaseVersion is set, releaseVersion will already contain the solution's version
- // That's because the version must be up to date even when loading the project individually
- return releaseVersion;
- }
- set {
- releaseVersion = value;
- NotifyModified ("Version");
- }
- }
-
- public bool SyncVersionWithSolution {
- get {
- return syncReleaseVersion;
- }
- set {
- syncReleaseVersion = value;
- if (syncReleaseVersion && ParentSolution != null)
- Version = ParentSolution.Version;
- NotifyModified ("SyncVersionWithSolution");
- }
- }
-
- [ItemProperty ("name")]
- public override string Name {
- get {
- return name ?? string.Empty;
- }
- set {
- if (name == value)
- return;
- string oldName = name;
- name = value;
- if (!Loading && ItemHandler.SyncFileName) {
- if (string.IsNullOrEmpty (fileName))
- FileName = value;
- else {
- string ext = fileName.Extension;
- FileName = fileName.ParentDirectory.Combine (value) + ext;
- }
- }
- OnNameChanged (new SolutionItemRenamedEventArgs (this, oldName, name));
- }
- }
-
- public virtual FilePath FileName {
- get {
- return fileName;
- }
- set {
- fileName = value;
- if (FileFormat != null)
- fileName = FileFormat.GetValidFileName (this, fileName);
- if (ItemHandler.SyncFileName)
- Name = fileName.FileNameWithoutExtension;
- NotifyModified ("FileName");
- }
- }
-
- public bool Enabled {
- get { return ParentSolution != null ? ParentSolution.IsSolutionItemEnabled (FileName) : true; }
- set {
- if (ParentSolution != null)
- ParentSolution.SetSolutionItemEnabled (FileName, value);
- }
- }
-
- public FileFormat FileFormat {
- get {
- if (ParentSolution != null) {
- if (ParentSolution.FileFormat.Format.SupportsMixedFormats && fileFormat != null)
- return fileFormat;
- return ParentSolution.FileFormat;
- }
- if (fileFormat == null)
- fileFormat = Services.ProjectService.GetDefaultFormat (this);
- return fileFormat;
- }
- set {
- if (ParentSolution != null && !ParentSolution.FileFormat.Format.SupportsMixedFormats)
- throw new InvalidOperationException ("The file format can't be changed when the item belongs to a solution.");
- InstallFormat (value);
- fileFormat.Format.ConvertToFormat (this);
- NeedsReload = false;
- NotifyModified ("FileFormat");
- }
- }
-
- public ProjectItemCollection Items {
- get { return items; }
- }
-
- internal ProjectItemCollection WildcardItems {
- get { return wildcardItems; }
- }
-
- /// <summary>
- /// Projects that need to be built before building this one
- /// </summary>
- /// <value>The dependencies.</value>
- public ItemCollection<SolutionEntityItem> ItemDependencies {
- get { return dependencies; }
- }
-
- public override IEnumerable<SolutionItem> GetReferencedItems (ConfigurationSelector configuration)
- {
- return base.GetReferencedItems (configuration).Concat (dependencies);
- }
-
- void IWorkspaceFileObject.ConvertToFormat (FileFormat format, bool convertChildren)
- {
- this.FileFormat = format;
- }
-
- public virtual bool SupportsFormat (FileFormat format)
- {
- return true;
- }
-
- internal void InstallFormat (FileFormat format)
- {
- fileFormat = format;
- if (fileName != FilePath.Null)
- fileName = fileFormat.GetValidFileName (this, fileName);
- }
-
- protected override void InitializeItemHandler ()
- {
- Services.ProjectService.GetDefaultFormat (this).Format.ConvertToFormat (this);
- }
-
- protected override FilePath GetDefaultBaseDirectory ( )
- {
- return FileName.IsNullOrEmpty ? FilePath.Empty : FileName.ParentDirectory;
- }
-
- public void Save (FilePath fileName, IProgressMonitor monitor)
- {
- FileName = fileName;
- Save (monitor);
- }
-
- public override void Save (IProgressMonitor monitor)
- {
- if (string.IsNullOrEmpty (FileName))
- throw new InvalidOperationException ("Project does not have a file name");
-
- try {
- fileStatusTracker.BeginSave ();
- Services.ProjectService.GetExtensionChain (this).Save (monitor, this);
- OnSaved (thisItemArgs);
- } finally {
- fileStatusTracker.EndSave ();
- }
- FileService.NotifyFileChanged (FileName);
- }
-
- protected override void OnEndLoad ()
- {
- base.OnEndLoad ();
- fileStatusTracker.ResetLoadTimes ();
-
- if (syncReleaseVersion && ParentSolution != null)
- releaseVersion = ParentSolution.Version;
- }
-
-
- internal bool IsSaved {
- get {
- return !string.IsNullOrEmpty (FileName) && File.Exists (FileName);
- }
- }
-
- public override bool NeedsReload {
- get { return fileStatusTracker.NeedsReload; }
- set { fileStatusTracker.NeedsReload = value; }
- }
-
- public virtual bool ItemFilesChanged {
- get { return fileStatusTracker.ItemFilesChanged; }
- }
-
- internal protected override BuildResult OnRunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
- {
- if (target == ProjectService.BuildTarget) {
- SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
- if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Build)) {
- conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.Build, configuration);
- return new BuildResult ();
- }
- } else if (target == ProjectService.CleanTarget) {
- SolutionItemConfiguration config = GetConfiguration (configuration) as SolutionItemConfiguration;
- if (config != null && config.CustomCommands.HasCommands (CustomCommandType.Clean)) {
- config.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.Clean, configuration);
- return new BuildResult ();
- }
- }
- return base.OnRunTarget (monitor, target, configuration);
- }
-
- protected internal virtual void OnSave (IProgressMonitor monitor)
- {
- ItemHandler.Save (monitor);
- }
-
- [Obsolete ("This method will be removed in future releases")]
- public void SetNeedsBuilding (bool value)
- {
- // Nothing to be done
- }
-
- public FilePath GetAbsoluteChildPath (FilePath relPath)
- {
- return relPath.ToAbsolute (BaseDirectory);
- }
-
- public FilePath GetRelativeChildPath (FilePath absPath)
- {
- return absPath.ToRelative (BaseDirectory);
- }
-
- public List<FilePath> GetItemFiles (bool includeReferencedFiles)
- {
- return Services.ProjectService.GetExtensionChain (this).GetItemFiles (this, includeReferencedFiles);
- }
-
- internal protected virtual List<FilePath> OnGetItemFiles (bool includeReferencedFiles)
- {
- List<FilePath> col = FileFormat.Format.GetItemFiles (this);
- if (!string.IsNullOrEmpty (FileName) && !col.Contains (FileName))
- col.Add (FileName);
- return col;
- }
-
- protected override void OnNameChanged (SolutionItemRenamedEventArgs e)
- {
- Solution solution = this.ParentSolution;
-
- if (solution != null) {
- foreach (DotNetProject project in solution.GetAllSolutionItems<DotNetProject>()) {
- if (project == this)
- continue;
-
- project.RenameReferences (e.OldName, e.NewName);
- }
- }
- fileStatusTracker.ResetLoadTimes ();
- base.OnNameChanged (e);
- }
-
- protected virtual void OnSaved (SolutionItemEventArgs args)
- {
- if (Saved != null)
- Saved (this, args);
- }
-
- public virtual string[] SupportedPlatforms {
- get {
- return new string [0];
- }
- }
-
- public virtual SolutionItemConfiguration GetConfiguration (ConfigurationSelector configuration)
- {
- return (SolutionItemConfiguration) configuration.GetConfiguration (this) ?? DefaultConfiguration;
- }
-
- ItemConfiguration IConfigurationTarget.DefaultConfiguration {
- get { return DefaultConfiguration; }
- set { DefaultConfiguration = (SolutionItemConfiguration) value; }
- }
-
- public SolutionItemConfiguration DefaultConfiguration {
- get {
- if (activeConfiguration == null && configurations.Count > 0) {
- return configurations[0];
- }
- return activeConfiguration;
- }
- set {
- if (activeConfiguration != value) {
- activeConfiguration = value;
- NotifyModified ("DefaultConfiguration");
- OnDefaultConfigurationChanged (new ConfigurationEventArgs (this, value));
- }
- }
- }
-
- public string DefaultConfigurationId {
- get {
- if (DefaultConfiguration != null)
- return DefaultConfiguration.Id;
- else
- return null;
- }
- set {
- DefaultConfiguration = GetConfiguration (new ItemConfigurationSelector (value));
- }
- }
-
- public virtual ReadOnlyCollection<string> GetConfigurations ()
- {
- List<string> configs = new List<string> ();
- foreach (SolutionItemConfiguration conf in Configurations)
- configs.Add (conf.Id);
- return configs.AsReadOnly ();
- }
-
- [ItemProperty ("Configurations")]
- [ItemProperty ("Configuration", ValueType=typeof(SolutionItemConfiguration), Scope="*")]
- public SolutionItemConfigurationCollection Configurations {
- get {
- return configurations;
- }
- }
-
- IItemConfigurationCollection IConfigurationTarget.Configurations {
- get {
- return Configurations;
- }
- }
-
- public SolutionItemConfiguration AddNewConfiguration (string name)
- {
- SolutionItemConfiguration config = CreateConfiguration (name);
- Configurations.Add (config);
- return config;
- }
-
- ItemConfiguration IConfigurationTarget.CreateConfiguration (string name)
- {
- return CreateConfiguration (name);
- }
-
- public virtual SolutionItemConfiguration CreateConfiguration (string name)
- {
- return new SolutionItemConfiguration (name);
- }
-
- void OnConfigurationAddedToCollection (object ob, ConfigurationEventArgs args)
- {
- NotifyModified ("Configurations");
- OnConfigurationAdded (new ConfigurationEventArgs (this, args.Configuration));
- if (ConfigurationsChanged != null)
- ConfigurationsChanged (this, EventArgs.Empty);
- if (activeConfiguration == null)
- DefaultConfigurationId = args.Configuration.Id;
- }
-
- void OnConfigurationRemovedFromCollection (object ob, ConfigurationEventArgs args)
- {
- if (activeConfiguration == args.Configuration) {
- if (Configurations.Count > 0)
- DefaultConfiguration = Configurations [0];
- else
- DefaultConfiguration = null;
- }
- NotifyModified ("Configurations");
- OnConfigurationRemoved (new ConfigurationEventArgs (this, args.Configuration));
- if (ConfigurationsChanged != null)
- ConfigurationsChanged (this, EventArgs.Empty);
- }
-
- public override StringTagModelDescription GetStringTagModelDescription (ConfigurationSelector conf)
- {
- StringTagModelDescription model = base.GetStringTagModelDescription (conf);
- SolutionItemConfiguration config = GetConfiguration (conf);
- if (config != null)
- model.Add (config.GetType ());
- else
- model.Add (typeof(SolutionItemConfiguration));
- return model;
- }
-
- public override StringTagModel GetStringTagModel (ConfigurationSelector conf)
- {
- StringTagModel source = base.GetStringTagModel (conf);
- SolutionItemConfiguration config = GetConfiguration (conf);
- if (config != null)
- source.Add (config);
- return source;
- }
-
- internal protected virtual void OnItemsAdded (IEnumerable<ProjectItem> objs)
- {
- NotifyModified ("Items");
- var args = new ProjectItemEventArgs ();
- args.AddRange (objs.Select (pi => new ProjectItemEventInfo (this, pi)));
- if (ProjectItemAdded != null)
- ProjectItemAdded (this, args);
- }
-
- internal protected virtual void OnItemsRemoved (IEnumerable<ProjectItem> objs)
- {
- NotifyModified ("Items");
- var args = new ProjectItemEventArgs ();
- args.AddRange (objs.Select (pi => new ProjectItemEventInfo (this, pi)));
- if (ProjectItemRemoved != null)
- ProjectItemRemoved (this, args);
- }
-
- protected virtual void OnDefaultConfigurationChanged (ConfigurationEventArgs args)
- {
- if (DefaultConfigurationChanged != null)
- DefaultConfigurationChanged (this, args);
- }
-
- protected virtual void OnConfigurationAdded (ConfigurationEventArgs args)
- {
- if (ConfigurationAdded != null)
- ConfigurationAdded (this, args);
- }
-
- protected virtual void OnConfigurationRemoved (ConfigurationEventArgs args)
- {
- if (ConfigurationRemoved != null)
- ConfigurationRemoved (this, args);
- }
-
- protected virtual void OnReloadRequired (SolutionItemEventArgs args)
- {
- fileStatusTracker.FireReloadRequired (args);
- }
-
- public event SolutionItemEventHandler Saved;
-
-/* public event EventHandler<SolutionItemEventArgs> ReloadRequired {
- add { fileStatusTracker.ReloadRequired += value; }
- remove { fileStatusTracker.ReloadRequired -= value; }
- }
-*/ }
-
- [Mono.Addins.Extension]
- class SolutionEntityItemTagProvider: StringTagProvider<SolutionEntityItem>, IStringTagProvider
- {
- public override IEnumerable<StringTagDescription> GetTags ()
- {
- yield return new StringTagDescription ("ProjectFile", "Project File");
- }
-
- public override object GetTagValue (SolutionEntityItem item, string tag)
- {
- switch (tag) {
- case "ITEMFILE":
- case "PROJECTFILE":
- case "PROJECTFILENAME":
- return item.FileName;
- }
- throw new NotSupportedException ();
- }
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionExtension.cs
new file mode 100644
index 0000000000..4da2bdf7d0
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionExtension.cs
@@ -0,0 +1,89 @@
+//
+// SolutionExtension.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using MonoDevelop.Core;
+using MonoDevelop.Core.Execution;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MonoDevelop.Projects.Formats.MSBuild;
+
+namespace MonoDevelop.Projects
+{
+ public class SolutionExtension: WorkspaceItemExtension
+ {
+ SolutionExtension next;
+
+ protected Solution Solution {
+ get { return (Solution) base.Item; }
+ }
+
+ internal protected override bool SupportsItem (WorkspaceItem item)
+ {
+ return item is Solution;
+ }
+
+ internal protected virtual Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return next.Build (monitor, configuration);
+ }
+
+ internal protected virtual Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return next.Clean (monitor, configuration);
+ }
+
+ internal protected virtual Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return next.Execute (monitor, context, configuration);
+ }
+
+ internal protected virtual bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return next.CanExecute (context, configuration);
+ }
+
+ internal protected virtual IEnumerable<ExecutionTarget> GetExecutionTargets (Solution solution, ConfigurationSelector configuration)
+ {
+ return next.GetExecutionTargets (solution, configuration);
+ }
+
+ internal protected virtual bool NeedsBuilding (ConfigurationSelector configuration)
+ {
+ return next.NeedsBuilding (configuration);
+ }
+
+ internal protected virtual void OnReadSolution (ProgressMonitor monitor, SlnFile file)
+ {
+ next.OnReadSolution (monitor, file);
+ }
+
+ internal protected virtual void OnWriteSolution (ProgressMonitor monitor, SlnFile file)
+ {
+ next.OnWriteSolution (monitor, file);
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolder.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolder.cs
index d4f9cb7e91..15942ba39c 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolder.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolder.cs
@@ -45,11 +45,12 @@ using MonoDevelop.Core.ProgressMonitoring;
using MonoDevelop.Projects;
using MonoDevelop.Projects.Extensions;
using MonoDevelop.Core.Serialization;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
[DataInclude (typeof(SolutionConfiguration))]
- public class SolutionFolder : SolutionItem
+ public class SolutionFolder : SolutionFolderItem
{
SolutionFolderItemCollection items;
SolutionFolderFileCollection files;
@@ -67,6 +68,11 @@ namespace MonoDevelop.Projects
}
}
+ protected override IEnumerable<WorkspaceObject> OnGetChildren ()
+ {
+ return Items;
+ }
+
internal SolutionFolderItemCollection GetItemsWithoutCreating ()
{
return items;
@@ -86,20 +92,17 @@ namespace MonoDevelop.Projects
get { return ParentFolder == null; }
}
- public override string Name {
- get {
- if (ParentFolder == null && ParentSolution != null)
- return ParentSolution.Name;
- else
- return name;
- }
- set {
- if (value != name) {
- string oldName = name;
- name = value;
- OnNameChanged (new SolutionItemRenamedEventArgs (this, oldName, name));
- }
- }
+ protected override string OnGetName ()
+ {
+ if (ParentFolder == null && ParentSolution != null)
+ return ParentSolution.Name;
+ else
+ return name;
+ }
+
+ protected override void OnSetName (string value)
+ {
+ name = value;
}
protected override FilePath GetDefaultBaseDirectory ( )
@@ -136,7 +139,7 @@ namespace MonoDevelop.Projects
{
FilePath path = null;
- foreach (SolutionItem it in Items) {
+ foreach (SolutionFolderItem it in Items) {
FilePath subdir;
if (it is SolutionFolder) {
SolutionFolder sf = (SolutionFolder) it;
@@ -184,25 +187,19 @@ namespace MonoDevelop.Projects
else
return null;
}
-
- internal override IDictionary InternalGetExtendedProperties {
- get {
- if (ParentSolution != null && ParentFolder == null)
- return ParentSolution.ExtendedProperties;
- else
- return base.InternalGetExtendedProperties;
- }
- }
-
- protected override void InitializeItemHandler ()
+
+ protected override IDictionary OnGetExtendedProperties ()
{
- SetItemHandler (new DummySolutionFolderHandler (this));
+ if (ParentSolution != null && ParentFolder == null)
+ return ParentSolution.ExtendedProperties;
+ else
+ return base.OnGetExtendedProperties ();
}
-
+
public override void Dispose()
{
if (items != null) {
- foreach (SolutionItem e in items)
+ foreach (SolutionFolderItem e in items)
e.Dispose ();
items = null;
}
@@ -210,30 +207,25 @@ namespace MonoDevelop.Projects
base.Dispose ();
}
- public SolutionItem ReloadItem (IProgressMonitor monitor, SolutionItem sitem)
+ public async Task<SolutionFolderItem> ReloadItem (ProgressMonitor monitor, SolutionFolderItem sitem)
{
if (Items.IndexOf (sitem) == -1)
throw new InvalidOperationException ("Solution item '" + sitem.Name + "' does not belong to folder '" + Name + "'");
- SolutionEntityItem item = sitem as SolutionEntityItem;
+ SolutionItem item = sitem as SolutionItem;
if (item != null) {
// Load the new item
- SolutionEntityItem newItem;
+ SolutionItem newItem;
try {
if (ParentSolution.IsSolutionItemEnabled (item.FileName))
- newItem = Services.ProjectService.ReadSolutionItem (monitor, item.FileName);
+ newItem = await Services.ProjectService.ReadSolutionItem (monitor, item.FileName);
else {
UnknownSolutionItem e = new UnloadedSolutionItem () {
FileName = item.FileName
};
- var ch = item.GetItemHandler () as MonoDevelop.Projects.Formats.MSBuild.MSBuildHandler;
- if (ch != null) {
- var h = new MonoDevelop.Projects.Formats.MSBuild.MSBuildHandler (ch.TypeGuid, ch.ItemId) {
- Item = e,
- };
- e.SetItemHandler (h);
- }
+ e.ItemId = item.ItemId;
+ e.TypeGuid = item.TypeGuid;
newItem = e;
}
} catch (Exception ex) {
@@ -249,7 +241,7 @@ namespace MonoDevelop.Projects
newItem.Dispose ();
// Find the replacement if it exists
- return Items.OfType<SolutionEntityItem> ().FirstOrDefault (it => it.FileName == item.FileName);
+ return Items.OfType<SolutionItem> ().FirstOrDefault (it => it.FileName == item.FileName);
}
// Replace in the file list
@@ -269,7 +261,7 @@ namespace MonoDevelop.Projects
return sitem;
}
- internal void NotifyItemAdded (SolutionItem item, bool newToSolution)
+ internal void NotifyItemAdded (SolutionFolderItem item, bool newToSolution)
{
ConnectChildEntryEvents (item);
@@ -277,7 +269,7 @@ namespace MonoDevelop.Projects
OnItemAdded (new SolutionItemChangeEventArgs (item, ParentSolution, false), newToSolution);
}
- void ConnectChildEntryEvents (SolutionItem item)
+ void ConnectChildEntryEvents (SolutionFolderItem item)
{
if (item is Project) {
Project project = item as Project;
@@ -303,42 +295,36 @@ namespace MonoDevelop.Projects
folder.ReferenceAddedToProject += NotifyReferenceAddedToProject;
}
- if (item is SolutionEntityItem) {
- ((SolutionEntityItem)item).Saved += NotifyItemSaved;
+ if (item is SolutionItem) {
+ ((SolutionItem)item).Saved += NotifyItemSaved;
// ((SolutionEntityItem)item).ReloadRequired += NotifyItemReloadRequired;
}
item.Modified += NotifyItemModified;
}
- public override void Save (IProgressMonitor monitor)
- {
- foreach (SolutionItem item in Items)
- item.Save (monitor);
- }
-
- public SolutionEntityItem AddItem (IProgressMonitor monitor, string filename)
+ public Task<SolutionItem> AddItem (ProgressMonitor monitor, string filename)
{
return AddItem (monitor, filename, false);
}
- public SolutionEntityItem AddItem (IProgressMonitor monitor, string filename, bool createSolutionConfigurations)
+ public async Task<SolutionItem> AddItem (ProgressMonitor monitor, string filename, bool createSolutionConfigurations)
{
- if (monitor == null) monitor = new NullProgressMonitor ();
- SolutionEntityItem entry = Services.ProjectService.ReadSolutionItem (monitor, filename);
+ if (monitor == null) monitor = new ProgressMonitor ();
+ SolutionItem entry = await Services.ProjectService.ReadSolutionItem (monitor, filename);
AddItem (entry, createSolutionConfigurations);
return entry;
}
- public void AddItem (SolutionItem item)
+ public void AddItem (SolutionFolderItem item)
{
AddItem (item, false);
}
- public void AddItem (SolutionItem item, bool createSolutionConfigurations)
+ public void AddItem (SolutionFolderItem item, bool createSolutionConfigurations)
{
Items.Add (item);
- SolutionEntityItem eitem = item as SolutionEntityItem;
+ SolutionItem eitem = item as SolutionItem;
if (eitem != null && createSolutionConfigurations && eitem.SupportsBuild ()) {
// Create new solution configurations for item configurations
foreach (ItemConfiguration iconf in eitem.Configurations) {
@@ -352,7 +338,7 @@ namespace MonoDevelop.Projects
if (!found) {
SolutionConfiguration sconf = new SolutionConfiguration (iconf.Id);
// Add all items to the new configuration
- foreach (var it in ParentSolution.GetAllSolutionItems<SolutionEntityItem> ())
+ foreach (var it in ParentSolution.GetAllItems<SolutionItem> ())
sconf.AddItem (it);
ParentSolution.Configurations.Add (sconf);
}
@@ -360,14 +346,14 @@ namespace MonoDevelop.Projects
}
}
- internal void NotifyItemRemoved (SolutionItem item, bool removedFromSolution)
+ internal void NotifyItemRemoved (SolutionFolderItem item, bool removedFromSolution)
{
DisconnectChildEntryEvents (item);
NotifyModified ("Items");
OnItemRemoved (new SolutionItemChangeEventArgs (item, ParentSolution, false), removedFromSolution);
}
- void DisconnectChildEntryEvents (SolutionItem entry)
+ void DisconnectChildEntryEvents (SolutionFolderItem entry)
{
if (entry is Project) {
Project pce = entry as Project;
@@ -393,35 +379,29 @@ namespace MonoDevelop.Projects
cce.ReferenceAddedToProject -= NotifyReferenceAddedToProject;
}
- if (entry is SolutionEntityItem) {
- ((SolutionEntityItem)entry).Saved -= NotifyItemSaved;
+ if (entry is SolutionItem) {
+ ((SolutionItem)entry).Saved -= NotifyItemSaved;
// ((SolutionEntityItem)entry).ReloadRequired -= NotifyItemReloadRequired;
}
entry.Modified -= NotifyItemModified;
}
- protected internal override void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ public void Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
}
-
- /// <remarks>
- /// Returns a collection containing all entries in this folder and
- /// undercombines
- /// </remarks>
- public ReadOnlyCollection<SolutionItem> GetAllItems ()
+
+ public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
{
- return GetAllItems<SolutionItem> ();
+ return false;
}
-
+
/// <remarks>
- /// Returns a collection containing all entries of the given type in this folder and
+ /// Returns a collection containing all entries in this folder and
/// undercombines
/// </remarks>
- public ReadOnlyCollection<T> GetAllItems<T> () where T: SolutionItem
+ public IEnumerable<SolutionFolderItem> GetAllItems ()
{
- List<T> list = new List<T> ();
- GetAllItems<T> (list, this);
- return list.AsReadOnly ();
+ return GetAllItems<SolutionFolderItem> ();
}
public ReadOnlyCollection<T> GetAllItemsWithTopologicalSort<T> (ConfigurationSelector configuration) where T: SolutionItem
@@ -447,24 +427,24 @@ namespace MonoDevelop.Projects
return SolutionItem.TopologicalSort<Project> (list, configuration);
}
- void GetAllItems<T> (List<T> list, SolutionItem item) where T: SolutionItem
+ void GetAllItems<T> (List<T> list, SolutionFolderItem item) where T: SolutionFolderItem
{
if (item is T) {
list.Add ((T)item);
}
if (item is SolutionFolder) {
- foreach (SolutionItem ce in ((SolutionFolder)item).Items)
+ foreach (SolutionFolderItem ce in ((SolutionFolder)item).Items)
GetAllItems<T> (list, ce);
}
}
public ReadOnlyCollection<SolutionItem> GetAllBuildableEntries (ConfigurationSelector configuration, bool topologicalSort, bool includeExternalReferences)
{
- List<SolutionItem> list = new List<SolutionItem> ();
+ var list = new List<SolutionItem> ();
GetAllBuildableEntries (list, configuration, includeExternalReferences);
if (topologicalSort)
- return TopologicalSort<SolutionItem> (list, configuration);
+ return SolutionItem.TopologicalSort<SolutionItem> (list, configuration);
else
return list.AsReadOnly ();
}
@@ -482,22 +462,25 @@ namespace MonoDevelop.Projects
if (conf == null)
return;
- foreach (SolutionItem item in Items) {
+ foreach (SolutionFolderItem item in Items) {
if (item is SolutionFolder)
((SolutionFolder)item).GetAllBuildableEntries (list, configuration, includeExternalReferences);
- else if ((item is SolutionEntityItem) && conf.BuildEnabledForItem ((SolutionEntityItem) item) && item.SupportsBuild ())
- GetAllBuildableReferences (list, item, configuration, includeExternalReferences);
+ else if ((item is SolutionItem) && conf.BuildEnabledForItem ((SolutionItem) item) && ((SolutionItem)item).SupportsBuild ())
+ GetAllBuildableReferences (list, (SolutionItem)item, configuration, includeExternalReferences, false);
}
}
- void GetAllBuildableReferences (List<SolutionItem> list, SolutionItem item, ConfigurationSelector configuration, bool includeExternalReferences)
+ void GetAllBuildableReferences (List<SolutionItem> list, SolutionItem item, ConfigurationSelector configuration, bool includeExternalReferences, bool isDirectReference)
{
if (list.Contains (item))
return;
+ // Skip unsupported projects which are not directly referenced by other (supported) projects
+ if (!isDirectReference && item.IsUnsupportedProject)
+ return;
list.Add (item);
if (includeExternalReferences) {
- foreach (SolutionItem it in item.GetReferencedItems (configuration))
- GetAllBuildableReferences (list, it, configuration, includeExternalReferences);
+ foreach (var it in item.GetReferencedItems (configuration))
+ GetAllBuildableReferences (list, it, configuration, includeExternalReferences, true);
}
}
@@ -538,19 +521,19 @@ namespace MonoDevelop.Projects
}
}
- public SolutionEntityItem FindSolutionItem (string fileName)
+ public SolutionItem FindSolutionItem (string fileName)
{
string path = Path.GetFullPath (fileName);
- foreach (SolutionItem it in Items) {
+ foreach (SolutionFolderItem it in Items) {
if (it is SolutionFolder) {
- SolutionEntityItem r = ((SolutionFolder)it).FindSolutionItem (fileName);
+ SolutionItem r = ((SolutionFolder)it).FindSolutionItem (fileName);
if (r != null)
return r;
}
- else if (it is SolutionEntityItem) {
- SolutionEntityItem se = (SolutionEntityItem) it;
+ else if (it is SolutionItem) {
+ SolutionItem se = (SolutionItem) it;
if (!string.IsNullOrEmpty (se.FileName) && path == Path.GetFullPath (se.FileName))
- return (SolutionEntityItem) it;
+ return (SolutionItem) it;
}
}
return null;
@@ -558,7 +541,7 @@ namespace MonoDevelop.Projects
public Project FindProjectByName (string name)
{
- foreach (SolutionItem it in Items) {
+ foreach (SolutionFolderItem it in Items) {
if (it is SolutionFolder) {
Project r = ((SolutionFolder)it).FindProjectByName (name);
if (r != null)
@@ -572,85 +555,42 @@ namespace MonoDevelop.Projects
return null;
}
- protected internal override BuildResult OnRunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ public async Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration)
{
- if (target == ProjectService.BuildTarget)
- return OnBuild (monitor, configuration);
- else if (target == ProjectService.CleanTarget) {
- OnClean (monitor, configuration);
+ if (ParentSolution == null)
return new BuildResult ();
- }
-
+ SolutionConfiguration conf = ParentSolution.GetConfiguration (configuration);
+ if (conf == null)
+ return new BuildResult ();
+
+ var res = new BuildResult { BuildCount = 0 };
+
ReadOnlyCollection<SolutionItem> allProjects;
-
try {
allProjects = GetAllBuildableEntries (configuration, true, true);
} catch (CyclicDependencyException) {
monitor.ReportError (GettextCatalog.GetString ("Cyclic dependencies are not supported."), null);
return new BuildResult ("", 1, 1);
}
-
- try {
- monitor.BeginTask (GettextCatalog.GetString ("Building Solution: {0} ({1})", Name, configuration.ToString ()), allProjects.Count);
-
- BuildResult cres = new BuildResult ();
- cres.BuildCount = 0;
- HashSet<SolutionItem> failedItems = new HashSet<SolutionItem> ();
-
- foreach (SolutionItem item in allProjects) {
- if (monitor.IsCancelRequested)
- break;
- if (!item.ContainsReferences (failedItems, configuration)) {
- BuildResult res = item.RunTarget (monitor, target, configuration);
- if (res != null) {
- cres.Append (res);
- if (res.ErrorCount > 0)
- failedItems.Add (item);
- }
- } else
- failedItems.Add (item);
- monitor.Step (1);
- }
- return cres;
- } finally {
- monitor.EndTask ();
- }
- }
-
- protected override void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration)
- {
- if (ParentSolution == null)
- return;
- SolutionConfiguration conf = ParentSolution.GetConfiguration (configuration);
- if (conf == null)
- return;
-
+ monitor.BeginTask (GettextCatalog.GetString ("Cleaning Solution: {0} ({1})", Name, configuration.ToString ()), allProjects.Count);
try {
- monitor.BeginTask (GettextCatalog.GetString ("Cleaning Solution: {0} ({1})", Name, configuration.ToString ()), Items.Count);
-
- foreach (SolutionItem item in Items) {
- if (item is SolutionFolder)
- item.Clean (monitor, configuration);
- else if (item is SolutionEntityItem) {
- SolutionEntityItem si = (SolutionEntityItem) item;
- // ce can be null if you add items to the root solution folder which
- // causes them to be placed in an autogenerated 'Project Items' folder
- SolutionConfigurationEntry ce = conf.GetEntryForItem (si);
- if (ce != null && ce.Build)
- si.Clean (monitor, ce.ItemConfigurationSelector);
- } else {
- item.Clean (monitor, configuration);
- }
+ foreach (var si in allProjects) {
+ // ce can be null if you add items to the root solution folder which
+ // causes them to be placed in an autogenerated 'Project Items' folder
+ SolutionConfigurationEntry ce = conf.GetEntryForItem (si);
+ if (ce != null && ce.Build)
+ res.Append (await si.Clean (monitor, ce.ItemConfigurationSelector));
monitor.Step (1);
}
}
finally {
monitor.EndTask ();
}
+ return res;
}
- protected override BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+ public async Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector configuration, bool buildReferencedTargets = false)
{
ReadOnlyCollection<SolutionItem> allProjects;
@@ -671,11 +611,11 @@ namespace MonoDevelop.Projects
HashSet<SolutionItem> failedItems = new HashSet<SolutionItem> ();
foreach (SolutionItem item in toBuild) {
- if (monitor.IsCancelRequested)
+ if (monitor.CancellationToken.IsCancellationRequested)
break;
if (!item.ContainsReferences (failedItems, configuration)) {
- BuildResult res = item.Build (monitor, configuration, false);
+ BuildResult res = await item.Build (monitor, configuration, false);
if (res != null) {
cres.Append (res);
if (res.ErrorCount > 0)
@@ -691,12 +631,17 @@ namespace MonoDevelop.Projects
}
}
+ public bool NeedsBuilding (ConfigurationSelector configuration)
+ {
+ return Items.OfType<IBuildTarget>().Any (t => t.NeedsBuilding (configuration));
+ }
+
protected internal override DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
{
// Return the min value, since that the last time all items in the
// folder were built
DateTime tim = DateTime.MaxValue;
- foreach (SolutionItem it in Items) {
+ foreach (SolutionFolderItem it in Items) {
DateTime t = it.GetLastBuildTime (configuration);
if (t < tim)
tim = t;
@@ -1020,12 +965,12 @@ namespace MonoDevelop.Projects
get { return folder.Name; }
}
- public BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ public Task<BuildResult> RunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration)
{
throw new NotImplementedException ();
}
- public void Save (IProgressMonitor monitor)
+ public Task Save (ProgressMonitor monitor)
{
throw new NotImplementedException ();
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItem.cs
new file mode 100644
index 0000000000..9dd7b25a7d
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItem.cs
@@ -0,0 +1,549 @@
+// SolutionItem.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@novell.com>
+//
+// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//
+
+using System;
+using System.Collections;
+using System.Xml;
+using MonoDevelop.Core;
+using MonoDevelop.Core.Serialization;
+using MonoDevelop.Projects.Extensions;
+using MonoDevelop.Core.StringParsing;
+using MonoDevelop.Projects.Policies;
+using System.Collections.Generic;
+using MonoDevelop.Projects.Formats.MSBuild;
+
+namespace MonoDevelop.Projects
+{
+ public abstract class SolutionFolderItem: WorkspaceObject, IExtendedDataItem, IPolicyProvider
+ {
+ SolutionFolder parentFolder;
+ Solution parentSolution;
+ SolutionFolder internalChildren;
+
+ [ProjectPathItemProperty ("BaseDirectory", DefaultValue=null)]
+ string baseDirectory;
+
+ [ItemProperty ("Policies", IsExternal = true, SkipEmpty = true)]
+ PolicyBag policies;
+
+ [ItemProperty ("UseMSBuildEngine")]
+ public bool? UseMSBuildEngine { get; set; }
+
+ PropertyBag userProperties;
+
+ internal List<string> UnresolvedProjectDependencies { get; set; }
+
+ [ItemProperty ("name")]
+ public new string Name {
+ get {
+ return base.Name;
+ }
+ set {
+ if (value != Name) {
+ var oldName = Name;
+ OnSetName (value);
+ OnNameChanged (new SolutionItemRenamedEventArgs (this, oldName, Name));
+ }
+ }
+ }
+
+ public string TypeGuid {
+ get;
+ set;
+ }
+
+ protected abstract void OnSetName (string value);
+
+ /// <summary>
+ /// Gets the solution to which this item belongs
+ /// </summary>
+ public Solution ParentSolution {
+ get {
+ if (parentFolder != null)
+ return parentFolder.ParentSolution;
+ return parentSolution;
+ }
+ internal set {
+ if (parentSolution != null && parentSolution != value)
+ NotifyUnboundFromSolution (true);
+ parentSolution = value;
+ NotifyBoundToSolution (true);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the base directory of this solution item
+ /// </summary>
+ /// <value>
+ /// The base directory.
+ /// </value>
+ /// <remarks>
+ /// The base directory is the directory where files belonging to this project
+ /// are placed. Notice that this directory may be different than the directory
+ /// where the project file is placed.
+ /// </remarks>
+ public new FilePath BaseDirectory {
+ get {
+ if (baseDirectory == null) {
+ FilePath dir = GetDefaultBaseDirectory ();
+ if (dir.IsNullOrEmpty)
+ dir = ".";
+ return dir.FullPath;
+ }
+ else
+ return baseDirectory;
+ }
+ set {
+ FilePath def = GetDefaultBaseDirectory ();
+ if (value != FilePath.Null && def != FilePath.Null && value.FullPath == def.FullPath)
+ baseDirectory = null;
+ else if (string.IsNullOrEmpty (value))
+ baseDirectory = null;
+ else
+ baseDirectory = value.FullPath;
+ NotifyModified ("BaseDirectory");
+ }
+ }
+
+ protected override string OnGetBaseDirectory ()
+ {
+ return BaseDirectory;
+ }
+
+ protected override string OnGetItemDirectory ()
+ {
+ FilePath dir = GetDefaultBaseDirectory ();
+ if (string.IsNullOrEmpty (dir))
+ dir = ".";
+ return dir.FullPath;
+ }
+
+ internal bool HasCustomBaseDirectory {
+ get { return baseDirectory != null; }
+ }
+
+ /// <summary>
+ /// Gets the default base directory.
+ /// </summary>
+ /// <remarks>
+ /// The base directory is the directory where files belonging to this project
+ /// are placed. Notice that this directory may be different than the directory
+ /// where the project file is placed.
+ /// </remarks>
+ protected virtual FilePath GetDefaultBaseDirectory ( )
+ {
+ return ParentSolution.BaseDirectory;
+ }
+
+ /// <summary>
+ /// Gets the identifier of this solution item
+ /// </summary>
+ /// <remarks>
+ /// The identifier is unique inside the solution
+ /// </remarks>
+ public string ItemId {
+ get {
+ if (itemId == null)
+ itemId = "{" + Guid.NewGuid ().ToString ().ToUpper () + "}";
+ return itemId;
+ }
+ set {
+ itemId = value;
+ }
+ }
+
+ string itemId;
+
+ /// <summary>
+ /// Gets policies.
+ /// </summary>
+ /// <remarks>
+ /// Returns a policy container which can be used to query policies specific for this
+ /// solution item. If a policy is not defined for this item, the inherited value will be returned.
+ /// </remarks>
+ public PolicyBag Policies {
+ get {
+ //newly created (i.e. not deserialised) SolutionItems may have a null PolicyBag
+ if (policies == null)
+ policies = new MonoDevelop.Projects.Policies.PolicyBag ();
+ //this is the easiest reliable place to associate a deserialised Policybag with its owner
+ policies.Owner = this;
+ return policies;
+ }
+ //setter so that a solution can deserialise the PropertyBag on its RootFolder
+ internal set {
+ policies = value;
+ }
+ }
+
+ PolicyContainer IPolicyProvider.Policies {
+ get {
+ return Policies;
+ }
+ }
+
+ /// <summary>
+ /// Gets solution item properties specific to the current user
+ /// </summary>
+ /// <remarks>
+ /// These properties are not stored in the project file, but in a separate file which is not to be shared
+ /// with other users.
+ /// User properties are only loaded when the project is loaded inside the IDE.
+ /// </remarks>
+ public PropertyBag UserProperties {
+ get {
+ if (userProperties == null)
+ userProperties = new PropertyBag ();
+ return userProperties;
+ }
+ }
+
+ /// <summary>
+ /// Initializes the user properties of the item
+ /// </summary>
+ /// <param name='properties'>
+ /// Properties to be set
+ /// </param>
+ /// <exception cref='InvalidOperationException'>
+ /// The user properties have already been set
+ /// </exception>
+ /// <remarks>
+ /// This method is used by the IDE to initialize the user properties when a project is loaded.
+ /// </remarks>
+ public void LoadUserProperties (PropertyBag properties)
+ {
+ if (userProperties != null)
+ throw new InvalidOperationException ("User properties already loaded.");
+ userProperties = properties;
+ }
+
+ /// <summary>
+ /// Gets the parent solution folder.
+ /// </summary>
+ public SolutionFolder ParentFolder {
+ get {
+ return parentFolder;
+ }
+ internal set {
+ if (parentFolder != null && parentFolder.ParentSolution != null && (value == null || value.ParentSolution != parentFolder.ParentSolution))
+ NotifyUnboundFromSolution (false);
+
+ parentFolder = value;
+ if (internalChildren != null) {
+ internalChildren.ParentFolder = value;
+ }
+ if (value != null && value.ParentSolution != null) {
+ NotifyBoundToSolution (false);
+ }
+ }
+ }
+
+ // Normally, the ParentFolder setter fires OnBoundToSolution. However, when deserializing, child
+ // ParentFolder hierarchies can become connected before the ParentSolution becomes set. This method
+ // enables us to recursively fire the OnBoundToSolution call in those cases.
+ void NotifyBoundToSolution (bool includeInternalChildren)
+ {
+ var folder = this as SolutionFolder;
+ if (folder != null) {
+ var items = folder.GetItemsWithoutCreating ();
+ if (items != null) {
+ foreach (var item in items) {
+ item.NotifyBoundToSolution (true);
+ }
+ }
+ }
+ if (includeInternalChildren && internalChildren != null) {
+ internalChildren.NotifyBoundToSolution (true);
+ }
+ OnBoundToSolution ();
+ }
+
+ void NotifyUnboundFromSolution (bool includeInternalChildren)
+ {
+ var folder = this as SolutionFolder;
+ if (folder != null) {
+ var items = folder.GetItemsWithoutCreating ();
+ if (items != null) {
+ foreach (var item in items) {
+ item.NotifyUnboundFromSolution (true);
+ }
+ }
+ }
+ if (includeInternalChildren && internalChildren != null) {
+ internalChildren.NotifyUnboundFromSolution (true);
+ }
+ OnUnboundFromSolution ();
+ }
+
+ /// <summary>
+ /// Releases all resource used by the <see cref="MonoDevelop.Projects.SolutionItem"/> object.
+ /// </summary>
+ /// <remarks>
+ /// Call <see cref="Dispose"/> when you are finished using the <see cref="MonoDevelop.Projects.SolutionItem"/>. The
+ /// <see cref="Dispose"/> method leaves the <see cref="MonoDevelop.Projects.SolutionItem"/> in an unusable state.
+ /// After calling <see cref="Dispose"/>, you must release all references to the
+ /// <see cref="MonoDevelop.Projects.SolutionItem"/> so the garbage collector can reclaim the memory that the
+ /// <see cref="MonoDevelop.Projects.SolutionItem"/> was occupying.
+ /// </remarks>
+ public override void Dispose ()
+ {
+ base.Dispose ();
+
+ if (userProperties != null) {
+ ((IDisposable)userProperties).Dispose ();
+ userProperties = null;
+ }
+
+ // parentFolder = null;
+ // parentSolution = null;
+ // internalChildren = null;
+ // policies = null;
+ }
+
+ /// <summary>
+ /// Gets the time of the last build
+ /// </summary>
+ /// <returns>
+ /// The last build time.
+ /// </returns>
+ /// <param name='configuration'>
+ /// Configuration for which to get the last build time.
+ /// </param>
+ public DateTime GetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return OnGetLastBuildTime (configuration);
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="MonoDevelop.Projects.SolutionItem"/> needs to be reload due to changes in project or solution file
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if needs reload; otherwise, <c>false</c>.
+ /// </value>
+ public virtual bool NeedsReload {
+ get {
+ if (ParentSolution != null)
+ return ParentSolution.NeedsReload;
+ else
+ return false;
+ }
+ set {
+ }
+ }
+
+ /// <summary>
+ /// Registers an internal child item.
+ /// </summary>
+ /// <param name='item'>
+ /// An item
+ /// </param>
+ /// <remarks>
+ /// Some kind of projects may be composed of several child projects.
+ /// By registering those child projects using this method, the child
+ /// projects will be plugged into the parent solution infrastructure
+ /// (so for example, the ParentSolution property for those projects
+ /// will return the correct value)
+ /// </remarks>
+ protected void RegisterInternalChild (SolutionFolderItem item)
+ {
+ if (internalChildren == null) {
+ internalChildren = new SolutionFolder ();
+ internalChildren.ParentFolder = parentFolder;
+ }
+ internalChildren.Items.Add (item);
+ }
+
+ /// <summary>
+ /// Unregisters an internal child item.
+ /// </summary>
+ /// <param name='item'>
+ /// The item
+ /// </param>
+ protected void UnregisterInternalChild (SolutionFolderItem item)
+ {
+ if (internalChildren != null)
+ internalChildren.Items.Remove (item);
+ }
+
+ /// <summary>
+ /// Gets the string tag model description for this solution item
+ /// </summary>
+ /// <returns>
+ /// The string tag model description
+ /// </returns>
+ /// <param name='conf'>
+ /// Configuration for which to get the string tag model description
+ /// </param>
+ public virtual StringTagModelDescription GetStringTagModelDescription (ConfigurationSelector conf)
+ {
+ StringTagModelDescription model = new StringTagModelDescription ();
+ model.Add (GetType ());
+ model.Add (typeof(Solution));
+ return model;
+ }
+
+ /// <summary>
+ /// Gets the string tag model for this solution item
+ /// </summary>
+ /// <returns>
+ /// The string tag model
+ /// </returns>
+ /// <param name='conf'>
+ /// Configuration for which to get the string tag model
+ /// </param>
+ public virtual StringTagModel GetStringTagModel (ConfigurationSelector conf)
+ {
+ StringTagModel source = new StringTagModel ();
+ source.Add (this);
+ if (ParentSolution != null)
+ source.Add (ParentSolution.GetStringTagModel ());
+ return source;
+ }
+
+ /// <summary>
+ /// Gets the author information for this solution item, inherited from the solution and global settings.
+ /// </summary>
+ public AuthorInformation AuthorInformation {
+ get {
+ if (ParentSolution != null)
+ return ParentSolution.AuthorInformation;
+ else
+ return AuthorInformation.Default;
+ }
+ }
+
+ internal MSBuildFileFormat SolutionFormat { get; private set; }
+
+ internal virtual void SetSolutionFormat (MSBuildFileFormat format, bool converting)
+ {
+ this.SolutionFormat = format;
+ }
+
+ public virtual bool HasSlnData {
+ get { return false; }
+ }
+
+ DataItem customSlnData;
+
+ public virtual DataItem WriteSlnData ()
+ {
+ return customSlnData;
+ }
+
+ public virtual void ReadSlnData (DataItem item)
+ {
+ customSlnData = item;
+ }
+
+ /// <summary>
+ /// Notifies that this solution item has been modified
+ /// </summary>
+ /// <param name='hint'>
+ /// Hint about which part of the solution item has been modified. This will typically be the property name.
+ /// </param>
+ public void NotifyModified (string hint)
+ {
+ OnModified (new SolutionItemModifiedEventArgs (this, hint));
+ }
+
+ /// <summary>
+ /// Raises the modified event.
+ /// </summary>
+ /// <param name='args'>
+ /// Arguments.
+ /// </param>
+ protected virtual void OnModified (SolutionItemModifiedEventArgs args)
+ {
+ if (Modified != null && !Disposed)
+ Modified (this, args);
+ }
+
+ /// <summary>
+ /// Raises the name changed event.
+ /// </summary>
+ /// <param name='e'>
+ /// Arguments.
+ /// </param>
+ protected virtual void OnNameChanged (SolutionItemRenamedEventArgs e)
+ {
+ NotifyModified ("Name");
+ if (NameChanged != null && !Disposed)
+ NameChanged (this, e);
+ }
+
+ /// <summary>
+ /// Initializes the item handler.
+ /// </summary>
+ /// <remarks>
+ /// This method is called the first time an item handler is requested.
+ /// Subclasses should override this method use SetItemHandler to
+ /// assign a handler to this item.
+ /// </remarks>
+ protected virtual void InitializeItemHandler ()
+ {
+ }
+
+ /// <summary>
+ /// Gets the time of the last build
+ /// </summary>
+ /// <returns>
+ /// The last build time.
+ /// </returns>
+ /// <param name='configuration'>
+ /// Configuration for which to get the last build time.
+ /// </param>
+ internal protected virtual DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return DateTime.MinValue;
+ }
+
+ /// <summary>
+ /// Called just after this item is bound to a solution
+ /// </summary>
+ protected virtual void OnBoundToSolution ()
+ {
+ }
+
+ /// <summary>
+ /// Called just before this item is removed from a solution (ParentSolution is still valid when this method is called)
+ /// </summary>
+ protected virtual void OnUnboundFromSolution ()
+ {
+ }
+
+ /// <summary>
+ /// Occurs when the name of the item changes
+ /// </summary>
+ public event SolutionItemRenamedEventHandler NameChanged;
+
+ /// <summary>
+ /// Occurs when the item is modified.
+ /// </summary>
+ public event SolutionItemModifiedEventHandler Modified;
+ }
+
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItemCollection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItemCollection.cs
index e6704c7a57..81b85305e1 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItemCollection.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionFolderItemCollection.cs
@@ -30,7 +30,7 @@ using System.Collections.ObjectModel;
namespace MonoDevelop.Projects
{
- public class SolutionFolderItemCollection: ItemCollection<SolutionItem>
+ public class SolutionFolderItemCollection: ItemCollection<SolutionFolderItem>
{
SolutionFolder parentFolder;
@@ -43,14 +43,14 @@ namespace MonoDevelop.Projects
this.parentFolder = parentFolder;
}
- internal void Replace (SolutionItem item, SolutionItem newItem)
+ internal void Replace (SolutionFolderItem item, SolutionFolderItem newItem)
{
int i = IndexOf (item);
Items [i] = newItem;
newItem.ParentFolder = parentFolder;
}
- protected override void OnItemAdded (SolutionItem item)
+ protected override void OnItemAdded (SolutionFolderItem item)
{
if (parentFolder != null) {
// If the item belongs to another solution, remove it from there.
@@ -74,7 +74,7 @@ namespace MonoDevelop.Projects
}
}
- protected override void OnItemRemoved (SolutionItem item)
+ protected override void OnItemRemoved (SolutionFolderItem item)
{
if (parentFolder != null) {
item.ParentFolder = null;
@@ -82,12 +82,12 @@ namespace MonoDevelop.Projects
}
}
- internal void InternalAdd (SolutionItem item)
+ internal void InternalAdd (SolutionFolderItem item)
{
Items.Add (item);
}
- internal void InternalRemove (SolutionItem item)
+ internal void InternalRemove (SolutionFolderItem item)
{
Items.Remove (item);
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
index 3dd753efab..4cf410e674 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
@@ -1,4 +1,4 @@
-// SolutionItem.cs
+// SolutionEntityItem.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
@@ -26,419 +26,301 @@
//
using System;
+using System.Linq;
+using System.Xml;
+using System.IO;
using System.Collections;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Xml;
+using System.Collections.Specialized;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Diagnostics;
using System.CodeDom.Compiler;
+
using MonoDevelop.Core;
+using MonoDevelop.Projects;
using MonoDevelop.Core.Serialization;
-using MonoDevelop.Projects.Extensions;
-using MonoDevelop.Core.Collections;
+using MonoDevelop.Projects.Extensions;
using MonoDevelop.Core.StringParsing;
-using MonoDevelop.Core.Instrumentation;
-using MonoDevelop.Projects.Policies;
using MonoDevelop.Core.Execution;
+using Mono.Addins;
+using MonoDevelop.Core.Instrumentation;
+using MonoDevelop.Core.Collections;
+using System.Threading.Tasks;
+using MonoDevelop.Projects.Formats.MSBuild;
namespace MonoDevelop.Projects
{
- public abstract class SolutionItem: IExtendedDataItem, IBuildTarget, ILoadController, IPolicyProvider
+ public abstract class SolutionItem : SolutionFolderItem, IWorkspaceFileObject, IConfigurationTarget, ILoadController, IBuildTarget
{
- SolutionFolder parentFolder;
- Solution parentSolution;
- ISolutionItemHandler handler;
+ internal object MemoryProbe = Counters.ItemsInMemory.CreateMemoryProbe ();
+
int loading;
- SolutionFolder internalChildren;
+ ProjectItemCollection items;
+ ProjectItemCollection wildcardItems;
+ ItemCollection<SolutionItem> dependencies = new ItemCollection<SolutionItem> ();
+
+ SolutionItemEventArgs thisItemArgs;
- [ProjectPathItemProperty ("BaseDirectory", DefaultValue=null)]
- string baseDirectory;
+ FileStatusTracker<SolutionItemEventArgs> fileStatusTracker;
+
+ FilePath fileName;
+ string name;
- Hashtable extendedProperties;
+ FileFormat fileFormat;
- [ItemProperty ("Policies", IsExternal = true, SkipEmpty = true)]
- MonoDevelop.Projects.Policies.PolicyBag policies;
+ SolutionItemConfiguration activeConfiguration;
+ SolutionItemConfigurationCollection configurations;
- [ItemProperty ("UseMSBuildEngine")]
- public bool? UseMSBuildEngine { get; set; }
-
- PropertyBag userProperties;
+ public event EventHandler ConfigurationsChanged;
+ public event ConfigurationEventHandler DefaultConfigurationChanged;
+ public event ConfigurationEventHandler ConfigurationAdded;
+ public event ConfigurationEventHandler ConfigurationRemoved;
+ public event EventHandler<ProjectItemEventArgs> ProjectItemAdded;
+ public event EventHandler<ProjectItemEventArgs> ProjectItemRemoved;
+
+ // When set, it means this item is saved as part of a global solution save operation
+ internal bool SavingSolution { get; set; }
- /// <summary>
- /// Initializes a new instance of the <see cref="MonoDevelop.Projects.SolutionItem"/> class.
- /// </summary>
- public SolutionItem()
+ public SolutionItem ()
{
+ var fmt = Services.ProjectService.FileFormats.GetFileFormat (MSBuildProjectService.DefaultFormat);
+ TypeGuid = MSBuildProjectService.GetTypeGuidForItem (this);
+
+ SetSolutionFormat ((MSBuildFileFormat)fmt.Format, true);
ProjectExtensionUtil.LoadControl (this);
+ items = new ProjectItemCollection (this);
+ wildcardItems = new ProjectItemCollection (this);
+ thisItemArgs = new SolutionItemEventArgs (this);
+ configurations = new SolutionItemConfigurationCollection (this);
+ configurations.ConfigurationAdded += OnConfigurationAddedToCollection;
+ configurations.ConfigurationRemoved += OnConfigurationRemovedFromCollection;
+ Counters.ItemsLoaded++;
+ fileStatusTracker = new FileStatusTracker<SolutionItemEventArgs> (this, OnReloadRequired, new SolutionItemEventArgs (this));
}
-
- /// <summary>
- /// Initializes a new instance of this item, using an xml element as template
- /// </summary>
- /// <param name='template'>
- /// The template
- /// </param>
- public virtual void InitializeFromTemplate (XmlElement template)
- {
- }
-
- /// <summary>
- /// Gets the handler for this solution item
- /// </summary>
- /// <value>
- /// The solution item handler.
- /// </value>
- /// <exception cref='InvalidOperationException'>
- /// Is thrown if there isn't a ISolutionItemHandler for this solution item
- /// </exception>
- protected internal ISolutionItemHandler ItemHandler {
+
+ SolutionItemExtension itemExtension;
+
+ SolutionItemExtension ItemExtension {
get {
- if (handler == null) {
- InitializeItemHandler ();
- if (handler == null)
- throw new InvalidOperationException ("No handler found for solution item of type: " + GetType ());
- }
- return handler;
+ if (itemExtension == null)
+ itemExtension = ExtensionChain.GetExtension<SolutionItemExtension> ();
+ return itemExtension;
}
}
-
- /// <summary>
- /// Sets the handler for this solution item
- /// </summary>
- /// <param name='handler'>
- /// A handler.
- /// </param>
- internal virtual void SetItemHandler (ISolutionItemHandler handler)
+
+ protected override IEnumerable<WorkspaceObjectExtension> CreateDefaultExtensions ()
{
- if (this.handler != null)
- this.handler.Dispose ();
- this.handler = handler;
+ foreach (var e in base.CreateDefaultExtensions ())
+ yield return e;
+ yield return new DefaultMSBuildItemExtension ();
}
-
- internal ISolutionItemHandler GetItemHandler ()
+
+ internal protected virtual IEnumerable<string> GetItemTypeGuids ()
{
- // Used to get the handler without lazy loading it
- return this.handler;
+ yield return TypeGuid;
}
-
- /// <summary>
- /// Gets the author information for this solution item, inherited from the solution and global settings.
- /// </summary>
- public AuthorInformation AuthorInformation {
- get {
- if (ParentSolution != null)
- return ParentSolution.AuthorInformation;
- else
- return AuthorInformation.Default;
- }
- }
-
- /// <summary>
- /// Gets a service instance of a given type
- /// </summary>
- /// <returns>
- /// The service.
- /// </returns>
- /// <typeparam name='T'>
- /// Type of the service
- /// </typeparam>
- /// <remarks>
- /// This method looks for an imlpementation of a service of the given type.
- /// </remarks>
- public T GetService<T> () where T: class
+
+ public override void Dispose ()
{
- return (T) GetService (typeof(T));
+ base.Dispose ();
+ Counters.ItemsLoaded--;
+
+ foreach (var item in items.Concat (wildcardItems)) {
+ IDisposable disp = item as IDisposable;
+ if (disp != null)
+ disp.Dispose ();
+ }
+
+ // items = null;
+ // wildcardItems = null;
+ // thisItemArgs = null;
+ // fileStatusTracker = null;
+ // fileFormat = null;
+ // activeConfiguration = null;
+ // configurations = null;
}
- /// <summary>
- /// Gets a service instance of a given type
- /// </summary>
- /// <returns>
- /// The service.
- /// </returns>
- /// <param name='t'>
- /// Type of the service
- /// </param>
- /// <remarks>
- /// This method looks for an imlpementation of a service of the given type.
- /// </remarks>
- public virtual object GetService (Type t)
+ void HandleSolutionItemAdded (object sender, SolutionItemChangeEventArgs e)
{
- return Services.ProjectService.GetExtensionChain (this).GetService (this, t);
- }
-
- /// <summary>
- /// Gets the solution to which this item belongs
- /// </summary>
- public Solution ParentSolution {
- get {
- if (parentFolder != null)
- return parentFolder.ParentSolution;
- return parentSolution;
- }
- internal set {
- parentSolution = value;
- NotifyBoundToSolution (true);
+ if (e.Reloading && dependencies.Count > 0 && (e.SolutionItem is SolutionItem) && (e.ReplacedItem is SolutionItem)) {
+ int i = dependencies.IndexOf ((SolutionItem)e.ReplacedItem);
+ if (i != -1)
+ dependencies [i] = (SolutionItem) e.SolutionItem;
}
}
- /// <summary>
- /// Gets a value indicating whether this item is currently being loaded from a file
- /// </summary>
- /// <remarks>
- /// While an item is loading, some events such as project file change events may be fired.
- /// This flag can be used to check if change events are caused by data being loaded.
- /// </remarks>
- public bool Loading {
- get { return loading > 0; }
- }
-
- /// <summary>
- /// Saves the solution item
- /// </summary>
- /// <param name='monitor'>
- /// A progress monitor.
- /// </param>
- public abstract void Save (IProgressMonitor monitor);
-
- /// <summary>
- /// Name of the solution item
- /// </summary>
- public abstract string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the base directory of this solution item
- /// </summary>
- /// <value>
- /// The base directory.
- /// </value>
- /// <remarks>
- /// The base directory is the directory where files belonging to this project
- /// are placed. Notice that this directory may be different than the directory
- /// where the project file is placed.
- /// </remarks>
- public FilePath BaseDirectory {
- get {
- if (baseDirectory == null) {
- FilePath dir = GetDefaultBaseDirectory ();
- if (dir.IsNullOrEmpty)
- dir = ".";
- return dir.FullPath;
- }
- else
- return baseDirectory;
- }
- set {
- FilePath def = GetDefaultBaseDirectory ();
- if (value != FilePath.Null && def != FilePath.Null && value.FullPath == def.FullPath)
- baseDirectory = null;
- else if (string.IsNullOrEmpty (value))
- baseDirectory = null;
- else
- baseDirectory = value.FullPath;
- NotifyModified ("BaseDirectory");
- }
+ void HandleSolutionItemRemoved (object sender, SolutionItemChangeEventArgs e)
+ {
+ if (!e.Reloading && (e.SolutionItem is SolutionItem))
+ dependencies.Remove ((SolutionItem)e.SolutionItem);
}
-
- /// <summary>
- /// Gets the directory where this solution item is placed
- /// </summary>
- public FilePath ItemDirectory {
- get {
- FilePath dir = GetDefaultBaseDirectory ();
- if (string.IsNullOrEmpty (dir))
- dir = ".";
- return dir.FullPath;
- }
+
+ void ILoadController.BeginLoad ()
+ {
+ loading++;
+ OnBeginLoad ();
}
-
- internal bool HasCustomBaseDirectory {
- get { return baseDirectory != null; }
- }
-
- /// <summary>
- /// Gets the default base directory.
- /// </summary>
- /// <remarks>
- /// The base directory is the directory where files belonging to this project
- /// are placed. Notice that this directory may be different than the directory
- /// where the project file is placed.
- /// </remarks>
- protected virtual FilePath GetDefaultBaseDirectory ( )
+
+ void ILoadController.EndLoad ()
{
- return ParentSolution.BaseDirectory;
+ loading--;
+ OnEndLoad ();
}
/// <summary>
- /// Gets the identifier of this solution item
+ /// Called when a load operation for this solution item has started
/// </summary>
- /// <remarks>
- /// The identifier is unique inside the solution
- /// </remarks>
- public string ItemId {
- get { return ItemHandler.ItemId; }
+ protected virtual void OnBeginLoad ()
+ {
}
-
+
/// <summary>
- /// Gets extended properties.
+ /// Called when a load operation for this solution item has finished
/// </summary>
- /// <remarks>
- /// This dictionary can be used by add-ins to store arbitrary information about this solution item.
- /// Keys and values can be of any type.
- /// If a value implements IDisposable, the value will be disposed when this solution item is disposed.
- /// Values in this dictionary won't be serialized, unless they are registered as serializable using
- /// the /MonoDevelop/ProjectModel/ExtendedProperties extension point.
- /// </remarks>
- public IDictionary ExtendedProperties {
- get { return InternalGetExtendedProperties; }
+ protected virtual void OnEndLoad ()
+ {
+ fileStatusTracker.ResetLoadTimes ();
+
+ if (syncReleaseVersion && ParentSolution != null)
+ releaseVersion = ParentSolution.Version;
}
+
+ [ItemProperty ("ReleaseVersion", DefaultValue="0.1")]
+ string releaseVersion = "0.1";
- /// <summary>
- /// Gets policies.
- /// </summary>
- /// <remarks>
- /// Returns a policy container which can be used to query policies specific for this
- /// solution item. If a policy is not defined for this item, the inherited value will be returned.
- /// </remarks>
- public MonoDevelop.Projects.Policies.PolicyBag Policies {
+ [ItemProperty ("SynchReleaseVersion", DefaultValue = true)]
+ bool syncReleaseVersion = true;
+
+ public string Version {
get {
- //newly created (i.e. not deserialised) SolutionItems may have a null PolicyBag
- if (policies == null)
- policies = new MonoDevelop.Projects.Policies.PolicyBag ();
- //this is the easiest reliable place to associate a deserialised Policybag with its owner
- policies.Owner = this;
- return policies;
+ // If syncReleaseVersion is set, releaseVersion will already contain the solution's version
+ // That's because the version must be up to date even when loading the project individually
+ return releaseVersion;
}
- //setter so that a solution can deserialise the PropertyBag on its RootFolder
- internal set {
- policies = value;
+ set {
+ releaseVersion = value;
+ NotifyModified ("Version");
}
}
- PolicyContainer IPolicyProvider.Policies {
+ public bool SyncVersionWithSolution {
get {
- return Policies;
+ return syncReleaseVersion;
+ }
+ set {
+ syncReleaseVersion = value;
+ if (syncReleaseVersion && ParentSolution != null)
+ Version = ParentSolution.Version;
+ NotifyModified ("SyncVersionWithSolution");
}
}
- /// <summary>
- /// Gets solution item properties specific to the current user
- /// </summary>
- /// <remarks>
- /// These properties are not stored in the project file, but in a separate file which is not to be shared
- /// with other users.
- /// User properties are only loaded when the project is loaded inside the IDE.
- /// </remarks>
- public PropertyBag UserProperties {
- get {
- if (userProperties == null)
- userProperties = new PropertyBag ();
- return userProperties;
+ protected override string OnGetName ()
+ {
+ return name ?? string.Empty;
+ }
+
+ protected override void OnSetName (string value)
+ {
+ name = value;
+ if (!Loading && SyncFileName) {
+ if (string.IsNullOrEmpty (fileName))
+ FileName = value;
+ else {
+ string ext = fileName.Extension;
+ FileName = fileName.ParentDirectory.Combine (value) + ext;
+ }
}
}
-
+
/// <summary>
- /// Initializes the user properties of the item
+ /// Returns a value indicating whether the name of the solution item should be the same as the name of the file
/// </summary>
- /// <param name='properties'>
- /// Properties to be set
- /// </param>
- /// <exception cref='InvalidOperationException'>
- /// The user properties have already been set
- /// </exception>
- /// <remarks>
- /// This method is used by the IDE to initialize the user properties when a project is loaded.
- /// </remarks>
- public void LoadUserProperties (PropertyBag properties)
- {
- if (userProperties != null)
- throw new InvalidOperationException ("User properties already loaded.");
- userProperties = properties;
+ /// <value>
+ /// <c>true</c> if the file name must be in sync with the solution item name; otherwise, <c>false</c>.
+ /// </value>
+ protected virtual bool SyncFileName {
+ get { return true; }
}
- /// <summary>
- /// Gets the parent solution folder.
- /// </summary>
- public SolutionFolder ParentFolder {
+ public virtual FilePath FileName {
get {
- return parentFolder;
+ return fileName;
}
- internal set {
- parentFolder = value;
- if (internalChildren != null) {
- internalChildren.ParentFolder = value;
- }
- if (value != null && value.ParentSolution != null) {
- NotifyBoundToSolution (false);
+ set {
+ if (FileFormat != null)
+ value = FileFormat.GetValidFileName (this, value);
+ if (value != fileName) {
+ fileName = value;
+ if (SyncFileName)
+ Name = fileName.FileNameWithoutExtension;
+ NotifyModified ("FileName");
}
}
}
- // Normally, the ParentFolder setter fires OnBoundToSolution. However, when deserializing, child
- // ParentFolder hierarchies can become connected before the ParentSolution becomes set. This method
- // enables us to recursively fire the OnBoundToSolution call in those cases.
- void NotifyBoundToSolution (bool includeInternalChildren)
- {
- var folder = this as SolutionFolder;
- if (folder != null) {
- var items = folder.GetItemsWithoutCreating ();
- if (items != null) {
- foreach (var item in items) {
- item.NotifyBoundToSolution (includeInternalChildren);
- }
+ public bool Enabled {
+ get { return ParentSolution != null ? ParentSolution.IsSolutionItemEnabled (FileName) : true; }
+ set {
+ if (ParentSolution != null)
+ ParentSolution.SetSolutionItemEnabled (FileName, value);
+ }
+ }
+
+ public FileFormat FileFormat {
+ get {
+ if (ParentSolution != null) {
+ if (ParentSolution.FileFormat.Format.SupportsMixedFormats && fileFormat != null)
+ return fileFormat;
+ return ParentSolution.FileFormat;
}
+ if (fileFormat == null)
+ fileFormat = Services.ProjectService.GetDefaultFormat (this);
+ return fileFormat;
}
- if (includeInternalChildren && internalChildren != null) {
- internalChildren.NotifyBoundToSolution (includeInternalChildren);
+ set {
+ if (ParentSolution != null && !ParentSolution.FileFormat.Format.SupportsMixedFormats)
+ throw new InvalidOperationException ("The file format can't be changed when the item belongs to a solution.");
+ InstallFormat (value);
+ fileFormat.Format.ConvertToFormat (this);
+ NeedsReload = false;
+ NotifyModified ("FileFormat");
}
- OnBoundToSolution ();
+ }
+
+ protected override object OnGetService (Type t)
+ {
+ return null;
}
+ public ProjectItemCollection Items {
+ get { return items; }
+ }
+ internal ProjectItemCollection WildcardItems {
+ get { return wildcardItems; }
+ }
+
/// <summary>
- /// Gets a value indicating whether this <see cref="MonoDevelop.Projects.SolutionItem"/> has been disposed.
+ /// Projects that need to be built before building this one
/// </summary>
- /// <value>
- /// <c>true</c> if disposed; otherwise, <c>false</c>.
- /// </value>
- internal protected bool Disposed { get; private set; }
+ /// <value>The dependencies.</value>
+ public ItemCollection<SolutionItem> ItemDependencies {
+ get { return dependencies; }
+ }
/// <summary>
- /// Releases all resource used by the <see cref="MonoDevelop.Projects.SolutionItem"/> object.
+ /// Gets a value indicating whether this item is currently being loaded from a file
/// </summary>
/// <remarks>
- /// Call <see cref="Dispose"/> when you are finished using the <see cref="MonoDevelop.Projects.SolutionItem"/>. The
- /// <see cref="Dispose"/> method leaves the <see cref="MonoDevelop.Projects.SolutionItem"/> in an unusable state.
- /// After calling <see cref="Dispose"/>, you must release all references to the
- /// <see cref="MonoDevelop.Projects.SolutionItem"/> so the garbage collector can reclaim the memory that the
- /// <see cref="MonoDevelop.Projects.SolutionItem"/> was occupying.
+ /// While an item is loading, some events such as project file change events may be fired.
+ /// This flag can be used to check if change events are caused by data being loaded.
/// </remarks>
- public virtual void Dispose ()
- {
- Disposed = true;
-
- if (extendedProperties != null) {
- foreach (object ob in extendedProperties.Values) {
- IDisposable disp = ob as IDisposable;
- if (disp != null)
- disp.Dispose ();
- }
- extendedProperties = null;
- }
- if (handler != null) {
- handler.Dispose ();
- // handler = null;
- }
- if (userProperties != null) {
- ((IDisposable)userProperties).Dispose ();
- userProperties = null;
- }
-
- // parentFolder = null;
- // parentSolution = null;
- // internalChildren = null;
- // policies = null;
+ public bool Loading {
+ get { return loading > 0; }
}
-
+
/// <summary>
/// Gets solution items referenced by this instance (items on which this item depends)
/// </summary>
@@ -448,94 +330,215 @@ namespace MonoDevelop.Projects
/// <param name='configuration'>
/// Configuration for which to get the referenced items
/// </param>
- public virtual IEnumerable<SolutionItem> GetReferencedItems (ConfigurationSelector configuration)
+ public IEnumerable<SolutionItem> GetReferencedItems (ConfigurationSelector configuration)
+ {
+ return ItemExtension.OnGetReferencedItems (configuration);
+ }
+
+ protected virtual IEnumerable<SolutionItem> OnGetReferencedItems (ConfigurationSelector configuration)
+ {
+ return dependencies;
+ }
+
+ Task IWorkspaceFileObject.ConvertToFormat (FileFormat format, bool convertChildren)
+ {
+ this.FileFormat = format;
+ return Task.FromResult (0);
+ }
+
+ public bool SupportsFormat (FileFormat format)
+ {
+ return ItemExtension.OnGetSupportsFormat (format);
+ }
+
+ protected virtual bool OnGetSupportsFormat (FileFormat format)
+ {
+ return true;
+ }
+
+ internal void InstallFormat (FileFormat format)
{
- return new SolutionItem [0];
+ fileFormat = format;
+ if (fileName != FilePath.Null)
+ fileName = fileFormat.GetValidFileName (this, fileName);
}
/// <summary>
- /// Runs a build or execution target.
+ /// Initializes a new instance of this item, using an xml element as template
/// </summary>
- /// <returns>
- /// The result of the operation
- /// </returns>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='target'>
- /// Name of the target
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to run the target
+ /// <param name='template'>
+ /// The template
/// </param>
- public BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ public void InitializeFromTemplate (XmlElement template)
{
- return Services.ProjectService.GetExtensionChain (this).RunTarget (monitor, this, target, configuration);
+ ItemExtension.OnInitializeFromTemplate (template);
}
-
- public bool SupportsTarget (string target)
+
+ protected virtual void OnInitializeFromTemplate (XmlElement template)
{
- return Services.ProjectService.GetExtensionChain (this).SupportsTarget (this, target);
}
- public bool SupportsBuild ()
+ public virtual void InitializeNew (ProjectCreateInformation projectCreateInfo, XmlElement projectOptions)
{
- return SupportsTarget (ProjectService.BuildTarget);
}
- public bool SupportsExecute ()
+ protected override FilePath GetDefaultBaseDirectory ( )
{
- return Services.ProjectService.GetExtensionChain (this).SupportsExecute (this);
+ return ItemExtension.OnGetDefaultBaseDirectory ();
}
+ internal Task LoadAsync (ProgressMonitor monitor, FilePath fileName, MSBuildFileFormat format)
+ {
+ FileName = fileName;
+ Name = Path.GetFileNameWithoutExtension (fileName);
+ SetSolutionFormat (format ?? new MSBuildFileFormatVS12 (), false);
+ return ItemExtension.OnLoad (monitor);
+ }
+
+ public void Save (ProgressMonitor monitor, FilePath fileName)
+ {
+ SaveAsync (monitor, fileName).Wait ();
+ }
+
+ public Task SaveAsync (ProgressMonitor monitor, FilePath fileName)
+ {
+ FileName = fileName;
+ return SaveAsync (monitor);
+ }
+
/// <summary>
- /// Cleans the files produced by this solution item
+ /// Saves the solution item
/// </summary>
/// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to clean the project
+ /// A progress monitor.
/// </param>
- public void Clean (IProgressMonitor monitor, ConfigurationSelector configuration)
+ public void Save (ProgressMonitor monitor)
{
- ITimeTracker tt = Counters.BuildProjectTimer.BeginTiming ("Cleaning " + Name);
+ ItemExtension.OnSave (monitor).Wait ();
+ }
+
+
+ public async Task SaveAsync (ProgressMonitor monitor)
+ {
+ await ItemExtension.OnSave (monitor);
+
+ if (HasSlnData && !SavingSolution && ParentSolution != null) {
+ // The project has data that has to be saved in the solution, but the solution is not being saved. Do it now.
+ await SolutionFormat.SlnFileFormat.WriteFile (ParentSolution.FileName, ParentSolution, false, monitor);
+ ParentSolution.NeedsReload = false;
+ }
+ }
+
+ async Task DoSave (ProgressMonitor monitor)
+ {
+ if (string.IsNullOrEmpty (FileName))
+ throw new InvalidOperationException ("Project does not have a file name");
+
try {
- //SolutionFolder handles the begin/end task itself, don't duplicate
- if (this is SolutionFolder) {
- RunTarget (monitor, ProjectService.CleanTarget, configuration);
- return;
- }
-
- try {
- SolutionEntityItem it = this as SolutionEntityItem;
- SolutionItemConfiguration iconf = it != null ? it.GetConfiguration (configuration) : null;
- string confName = iconf != null ? iconf.Id : configuration.ToString ();
- monitor.BeginTask (GettextCatalog.GetString ("Cleaning: {0} ({1})", Name, confName), 1);
- RunTarget (monitor, ProjectService.CleanTarget, configuration);
- } finally {
- monitor.EndTask ();
- }
+ fileStatusTracker.BeginSave ();
+ await OnSave (monitor);
+ OnSaved (thisItemArgs);
+ } finally {
+ fileStatusTracker.EndSave ();
}
- finally {
- tt.End ();
+ FileService.NotifyFileChanged (FileName);
+ }
+
+ internal bool IsSaved {
+ get {
+ return !string.IsNullOrEmpty (FileName) && File.Exists (FileName);
}
}
+ public override bool NeedsReload {
+ get { return fileStatusTracker.NeedsReload; }
+ set { fileStatusTracker.NeedsReload = value; }
+ }
+
+ public virtual bool ItemFilesChanged {
+ get { return ItemExtension.ItemFilesChanged; }
+ }
+
+ bool BaseItemFilesChanged {
+ get { return fileStatusTracker.ItemFilesChanged; }
+ }
+
+ public bool SupportsBuild ()
+ {
+ return ItemExtension.OnSupportsBuild ();
+ }
+
+ protected virtual bool OnGetSupportsBuild ()
+ {
+ return true;
+ }
+
+ public bool SupportsExecute ()
+ {
+ return ItemExtension.OnSupportsExecute ();
+ }
+
+ protected virtual bool OnGetSupportsExecute ()
+ {
+ return true;
+ }
+
+ public virtual bool SupportsConfigurations ()
+ {
+ // TODO NPM: -> extension chain
+ return SupportsBuild ();
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this project is supported.
+ /// </summary>
+ /// <remarks>
+ /// Unsupported projects are shown in the solution pad, but operations such as building on executing won't be available.
+ /// </remarks>
+ public bool IsUnsupportedProject { get; protected set; }
+
+ /// <summary>
+ /// Gets a message that explain why the project is not supported (when IsUnsupportedProject returns true)
+ /// </summary>
+ public string UnsupportedProjectMessage {
+ get { return IsUnsupportedProject ? (loadError ?? GettextCatalog.GetString ("Unknown project type")) : ""; }
+ set { loadError = value; }
+ }
+ string loadError;
+
+ public bool NeedsBuilding (ConfigurationSelector configuration)
+ {
+ return ItemExtension.OnNeedsBuilding (configuration);
+ }
+
+ internal protected virtual bool OnGetNeedsBuilding (ConfigurationSelector configuration)
+ {
+ return false;
+ }
+
+ public void SetNeedsBuilding (ConfigurationSelector configuration)
+ {
+ OnSetNeedsBuilding (configuration);
+ }
+
+ protected virtual void OnSetNeedsBuilding (ConfigurationSelector configuration)
+ {
+ }
+
/// <summary>
/// Builds the solution item
/// </summary>
/// <param name='monitor'>
/// A progress monitor
/// </param>
- /// <param name='configuration'>
+ /// <param name='solutionConfiguration'>
/// Configuration to use to build the project
/// </param>
- public BuildResult Build (IProgressMonitor monitor, ConfigurationSelector configuration)
+ public Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector solutionConfiguration)
{
- return Build (monitor, configuration, false);
+ return Build (monitor, solutionConfiguration, false);
}
-
+
/// <summary>
/// Builds the solution item
/// </summary>
@@ -548,54 +551,47 @@ namespace MonoDevelop.Projects
/// <param name='buildReferences'>
/// When set to <c>true</c>, the referenced items will be built before building this item
/// </param>
- public BuildResult Build (IProgressMonitor monitor, ConfigurationSelector solutionConfiguration, bool buildReferences)
+ public async Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector solutionConfiguration, bool buildReferences)
{
ITimeTracker tt = Counters.BuildProjectTimer.BeginTiming ("Building " + Name);
try {
if (!buildReferences) {
- //SolutionFolder's OnRunTarget handles the begin/end task itself, don't duplicate
- if (this is SolutionFolder) {
- return RunTarget (monitor, ProjectService.BuildTarget, solutionConfiguration);
- }
-
try {
- SolutionEntityItem it = this as SolutionEntityItem;
- SolutionItemConfiguration iconf = it != null ? it.GetConfiguration (solutionConfiguration) : null;
+ SolutionItemConfiguration iconf = GetConfiguration (solutionConfiguration);
string confName = iconf != null ? iconf.Id : solutionConfiguration.ToString ();
monitor.BeginTask (GettextCatalog.GetString ("Building: {0} ({1})", Name, confName), 1);
-
- // This will end calling OnBuild ()
- return RunTarget (monitor, ProjectService.BuildTarget, solutionConfiguration);
-
+
+ return await InternalBuild (monitor, solutionConfiguration);
+
} finally {
monitor.EndTask ();
}
}
-
+
// Get a list of all items that need to be built (including this),
// and build them in the correct order
-
- List<SolutionItem> referenced = new List<SolutionItem> ();
- Set<SolutionItem> visited = new Set<SolutionItem> ();
+
+ var referenced = new List<SolutionItem> ();
+ var visited = new Set<SolutionItem> ();
GetBuildableReferencedItems (visited, referenced, this, solutionConfiguration);
-
- ReadOnlyCollection<SolutionItem> sortedReferenced = SolutionFolder.TopologicalSort (referenced, solutionConfiguration);
-
+
+ var sortedReferenced = TopologicalSort (referenced, solutionConfiguration);
+
BuildResult cres = new BuildResult ();
cres.BuildCount = 0;
- HashSet<SolutionItem> failedItems = new HashSet<SolutionItem> ();
-
+ var failedItems = new HashSet<SolutionItem> ();
+
monitor.BeginTask (null, sortedReferenced.Count);
- foreach (SolutionItem p in sortedReferenced) {
+ foreach (var p in sortedReferenced) {
if (!p.ContainsReferences (failedItems, solutionConfiguration)) {
- BuildResult res = p.Build (monitor, solutionConfiguration, false);
+ BuildResult res = await p.Build (monitor, solutionConfiguration, false);
cres.Append (res);
if (res.ErrorCount > 0)
failedItems.Add (p);
} else
failedItems.Add (p);
monitor.Step (1);
- if (monitor.IsCancelRequested)
+ if (monitor.CancellationToken.IsCancellationRequested)
break;
}
monitor.EndTask ();
@@ -604,40 +600,258 @@ namespace MonoDevelop.Projects
tt.End ();
}
}
-
+
+ async Task<BuildResult> InternalBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ if (IsUnsupportedProject) {
+ var r = new BuildResult ();
+ r.AddError (UnsupportedProjectMessage);
+ return r;
+ }
+
+ SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
+ if (conf != null) {
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.BeforeBuild, null, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.BeforeBuild, configuration)) {
+ var r = new BuildResult ();
+ r.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ return r;
+ }
+ }
+ }
+
+ if (monitor.CancellationToken.IsCancellationRequested)
+ return new BuildResult (new CompilerResults (null), "");
+
+ BuildResult res = await ItemExtension.OnBuild (monitor, configuration);
+
+ if (conf != null && !monitor.CancellationToken.IsCancellationRequested && !res.Failed) {
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.AfterBuild, null, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.AfterBuild, configuration))
+ res.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ }
+ }
+
+ return res;
+ }
+
+ /// <summary>
+ /// Builds the solution item
+ /// </summary>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to build the project
+ /// </param>
+ protected virtual Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Task.FromResult (BuildResult.Success);
+ }
+
+ void GetBuildableReferencedItems (Set<SolutionItem> visited, List<SolutionItem> referenced, SolutionItem item, ConfigurationSelector configuration)
+ {
+ if (!visited.Add(item))
+ return;
+
+ referenced.Add (item);
+
+ foreach (var ritem in item.GetReferencedItems (configuration))
+ GetBuildableReferencedItems (visited, referenced, ritem, configuration);
+ }
+
internal bool ContainsReferences (HashSet<SolutionItem> items, ConfigurationSelector conf)
{
- foreach (SolutionItem it in GetReferencedItems (conf))
+ foreach (var it in GetReferencedItems (conf))
if (items.Contains (it))
return true;
return false;
}
/// <summary>
- /// Gets the time of the last build
+ /// Cleans the files produced by this solution item
+ /// </summary>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to clean the project
+ /// </param>
+ public async Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ ITimeTracker tt = Counters.BuildProjectTimer.BeginTiming ("Cleaning " + Name);
+ try {
+ try {
+ SolutionItemConfiguration iconf = GetConfiguration (configuration);
+ string confName = iconf != null ? iconf.Id : configuration.ToString ();
+ monitor.BeginTask (GettextCatalog.GetString ("Cleaning: {0} ({1})", Name, confName), 1);
+
+ SolutionItemConfiguration conf = GetConfiguration (configuration);
+ if (conf != null) {
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.BeforeClean, null, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.BeforeClean, configuration)) {
+ var r = new BuildResult ();
+ r.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ return r;
+ }
+ }
+ }
+
+ if (monitor.CancellationToken.IsCancellationRequested)
+ return BuildResult.Success;
+
+ var res = await ItemExtension.OnClean (monitor, configuration);
+
+ if (conf != null && !monitor.CancellationToken.IsCancellationRequested) {
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.AfterClean, null, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.AfterClean, configuration))
+ res.AddError (GettextCatalog.GetString ("Custom command execution failed"));
+ }
+ }
+ return res;
+
+ } finally {
+ monitor.EndTask ();
+ }
+ }
+ finally {
+ tt.End ();
+ }
+ }
+
+ /// <summary>
+ /// Cleans the files produced by this solution item
+ /// </summary>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to clean the project
+ /// </param>
+ protected virtual Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Task.FromResult (BuildResult.Success);
+ }
+
+ /// <summary>
+ /// Sorts a collection of solution items, taking into account the dependencies between them
/// </summary>
/// <returns>
- /// The last build time.
+ /// The sorted collection of items
/// </returns>
+ /// <param name='items'>
+ /// Items to sort
+ /// </param>
/// <param name='configuration'>
- /// Configuration for which to get the last build time.
+ /// A configuration
/// </param>
- public DateTime GetLastBuildTime (ConfigurationSelector configuration)
+ /// <remarks>
+ /// This methods sorts a collection of items, ensuring that every item is placed after all the items
+ /// on which it depends.
+ /// </remarks>
+ public static ReadOnlyCollection<T> TopologicalSort<T> (IEnumerable<T> items, ConfigurationSelector configuration) where T: SolutionItem
+ {
+ IList<T> allItems;
+ allItems = items as IList<T>;
+ if (allItems == null)
+ allItems = new List<T> (items);
+
+ List<T> sortedEntries = new List<T> ();
+ bool[] inserted = new bool[allItems.Count];
+ bool[] triedToInsert = new bool[allItems.Count];
+ for (int i = 0; i < allItems.Count; ++i) {
+ if (!inserted[i])
+ Insert<T> (i, allItems, sortedEntries, inserted, triedToInsert, configuration);
+ }
+ return sortedEntries.AsReadOnly ();
+ }
+
+ static void Insert<T> (int index, IList<T> allItems, List<T> sortedItems, bool[] inserted, bool[] triedToInsert, ConfigurationSelector solutionConfiguration) where T: SolutionItem
{
- return OnGetLastBuildTime (configuration);
+ if (triedToInsert[index]) {
+ throw new CyclicDependencyException ();
+ }
+ triedToInsert[index] = true;
+ var insertItem = allItems[index];
+
+ foreach (var reference in insertItem.GetReferencedItems (solutionConfiguration)) {
+ for (int j=0; j < allItems.Count; ++j) {
+ SolutionFolderItem checkItem = allItems[j];
+ if (reference == checkItem) {
+ if (!inserted[j])
+ Insert (j, allItems, sortedItems, inserted, triedToInsert, solutionConfiguration);
+ break;
+ }
+ }
+ }
+ sortedItems.Add (insertItem);
+ inserted[index] = true;
}
-
- void GetBuildableReferencedItems (Set<SolutionItem> visited, List<SolutionItem> referenced, SolutionItem item, ConfigurationSelector configuration)
- {
- if (!visited.Add(item))
+
+ /// <summary>
+ /// Executes this solution item
+ /// </summary>
+ /// <param name='monitor'>
+ /// A progress monitor
+ /// </param>
+ /// <param name='context'>
+ /// An execution context
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to execute the item
+ /// </param>
+ public async Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
+ if (conf != null) {
+ ExecutionContext localContext = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, context.ConsoleFactory, context.ExecutionTarget);
+
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.BeforeExecute, localContext, configuration)) {
+ if (!await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.BeforeExecute, localContext, configuration))
+ return;
+ }
+ }
+
+ if (monitor.CancellationToken.IsCancellationRequested)
return;
-
- referenced.Add (item);
- foreach (SolutionItem ritem in item.GetReferencedItems (configuration))
- GetBuildableReferencedItems (visited, referenced, ritem, configuration);
+ await ItemExtension.OnExecute (monitor, context, configuration);
+
+ if (conf != null && !monitor.CancellationToken.IsCancellationRequested) {
+ ExecutionContext localContext = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, context.ConsoleFactory, context.ExecutionTarget);
+
+ if (conf.CustomCommands.CanExecute (this, CustomCommandType.AfterExecute, localContext, configuration))
+ await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.AfterExecute, localContext, configuration);
+ }
}
-
+
+ /// <summary>
+ /// Determines whether this solution item can be executed using the specified context and configuration.
+ /// </summary>
+ /// <returns>
+ /// <c>true</c> if this instance can be executed; otherwise, <c>false</c>.
+ /// </returns>
+ /// <param name='context'>
+ /// An execution context
+ /// </param>
+ /// <param name='configuration'>
+ /// Configuration to use to execute the item
+ /// </param>
+ public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return !IsUnsupportedProject && ItemExtension.OnGetCanExecute (context, configuration);
+ }
+
+ async Task DoExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
+ if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Execute)) {
+ await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.Execute, context, configuration);
+ return;
+ }
+ await OnExecute (monitor, context, configuration);
+ }
+
/// <summary>
/// Executes this solution item
/// </summary>
@@ -650,11 +864,19 @@ namespace MonoDevelop.Projects
/// <param name='configuration'>
/// Configuration to use to execute the item
/// </param>
- public void Execute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ protected virtual Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
- Services.ProjectService.GetExtensionChain (this).Execute (monitor, this, context, configuration);
+ return Task.FromResult (0);
}
-
+
+ bool DoGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration;
+ if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Execute))
+ return conf.CustomCommands.CanExecute (this, CustomCommandType.Execute, context, configuration);
+ return OnGetCanExecute (context, configuration);
+ }
+
/// <summary>
/// Determines whether this solution item can be executed using the specified context and configuration.
/// </summary>
@@ -667,11 +889,9 @@ namespace MonoDevelop.Projects
/// <param name='configuration'>
/// Configuration to use to execute the item
/// </param>
- public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
{
- if (!SupportsExecute ())
- return false;
- return Services.ProjectService.GetExtensionChain (this).CanExecute (this, context, configuration);
+ return ItemExtension.OnGetCanExecute (context, configuration);
}
/// <summary>
@@ -681,7 +901,12 @@ namespace MonoDevelop.Projects
/// <param name="configuration">The configuration.</param>
public IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration)
{
- return Services.ProjectService.GetExtensionChain (this).GetExecutionTargets (this, configuration);
+ return ItemExtension.OnGetExecutionTargets (configuration);
+ }
+
+ protected void NotifyExecutionTargetsChanged ()
+ {
+ ItemExtension.OnExecutionTargetsChanged ();
}
public event EventHandler ExecutionTargetsChanged;
@@ -691,429 +916,480 @@ namespace MonoDevelop.Projects
if (ExecutionTargetsChanged != null)
ExecutionTargetsChanged (this, EventArgs.Empty);
}
-
- /// <summary>
- /// Checks if this solution item has modified files and has to be built
- /// </summary>
- /// <returns>
- /// <c>true</c> if the solution item has to be built
- /// </returns>
- /// <param name='configuration'>
- /// Configuration for which to do the check
- /// </param>
- [Obsolete ("This method will be removed in future releases")]
- public bool NeedsBuilding (ConfigurationSelector configuration)
+
+ protected virtual Task OnLoad (ProgressMonitor monitor)
{
- return true;
+ return Task.FromResult (0);
}
- internal bool InternalCheckNeedsBuild (ConfigurationSelector configuration)
+ protected internal virtual Task OnSave (ProgressMonitor monitor)
{
- using (Counters.NeedsBuildingTimer.BeginTiming ("NeedsBuilding check for " + Name)) {
- return Services.ProjectService.GetExtensionChain (this).GetNeedsBuilding (this, configuration);
- }
+ return Task.FromResult (0);
}
- /// <summary>
- /// States whether this solution item needs to be built or not
- /// </summary>
- /// <param name='value'>
- /// Whether this solution item needs to be built or not
- /// </param>
- /// <param name='configuration'>
- /// Configuration for which to set the flag
- /// </param>
- [Obsolete ("This method will be removed in future releases")]
- public void SetNeedsBuilding (bool value, ConfigurationSelector configuration)
+ public FilePath GetAbsoluteChildPath (FilePath relPath)
{
- // Nothing to be done.
+ return relPath.ToAbsolute (BaseDirectory);
}
-
- /// <summary>
- /// Gets or sets a value indicating whether this <see cref="MonoDevelop.Projects.SolutionItem"/> needs to be reload due to changes in project or solution file
- /// </summary>
- /// <value>
- /// <c>true</c> if needs reload; otherwise, <c>false</c>.
- /// </value>
- public virtual bool NeedsReload {
- get {
- if (ParentSolution != null)
- return ParentSolution.NeedsReload;
- else
- return false;
- }
- set {
- }
+
+ public FilePath GetRelativeChildPath (FilePath absPath)
+ {
+ return absPath.ToRelative (BaseDirectory);
}
-
- /// <summary>
- /// Registers an internal child item.
- /// </summary>
- /// <param name='item'>
- /// An item
- /// </param>
- /// <remarks>
- /// Some kind of projects may be composed of several child projects.
- /// By registering those child projects using this method, the child
- /// projects will be plugged into the parent solution infrastructure
- /// (so for example, the ParentSolution property for those projects
- /// will return the correct value)
- /// </remarks>
- protected void RegisterInternalChild (SolutionItem item)
+
+ public IEnumerable<FilePath> GetItemFiles (bool includeReferencedFiles)
{
- if (internalChildren == null) {
- internalChildren = new SolutionFolder ();
- internalChildren.ParentFolder = parentFolder;
- }
- internalChildren.Items.Add (item);
+ return ItemExtension.OnGetItemFiles (includeReferencedFiles);
}
-
- /// <summary>
- /// Unregisters an internal child item.
- /// </summary>
- /// <param name='item'>
- /// The item
- /// </param>
- protected void UnregisterInternalChild (SolutionItem item)
+
+ protected virtual IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
{
- if (internalChildren != null)
- internalChildren.Items.Remove (item);
+ List<FilePath> col = FileFormat.Format.GetItemFiles (this);
+ if (!string.IsNullOrEmpty (FileName) && !col.Contains (FileName))
+ col.Add (FileName);
+ return col;
}
-
- /// <summary>
- /// Gets the string tag model description for this solution item
- /// </summary>
- /// <returns>
- /// The string tag model description
- /// </returns>
- /// <param name='conf'>
- /// Configuration for which to get the string tag model description
- /// </param>
- public virtual StringTagModelDescription GetStringTagModelDescription (ConfigurationSelector conf)
+
+ protected override void OnNameChanged (SolutionItemRenamedEventArgs e)
{
- StringTagModelDescription model = new StringTagModelDescription ();
- model.Add (GetType ());
- model.Add (typeof(Solution));
- return model;
+ Solution solution = this.ParentSolution;
+
+ if (solution != null) {
+ foreach (DotNetProject project in solution.GetAllItems<DotNetProject>()) {
+ if (project == this)
+ continue;
+
+ project.RenameReferences (e.OldName, e.NewName);
+ }
+ }
+ fileStatusTracker.ResetLoadTimes ();
+ base.OnNameChanged (e);
}
- /// <summary>
- /// Gets the string tag model for this solution item
- /// </summary>
- /// <returns>
- /// The string tag model
- /// </returns>
- /// <param name='conf'>
- /// Configuration for which to get the string tag model
- /// </param>
- public virtual StringTagModel GetStringTagModel (ConfigurationSelector conf)
+ protected virtual void OnSaved (SolutionItemEventArgs args)
{
- StringTagModel source = new StringTagModel ();
- source.Add (this);
- if (ParentSolution != null)
- source.Add (ParentSolution.GetStringTagModel ());
- return source;
+ if (Saved != null)
+ Saved (this, args);
}
- /// <summary>
- /// Sorts a collection of solution items, taking into account the dependencies between them
- /// </summary>
- /// <returns>
- /// The sorted collection of items
- /// </returns>
- /// <param name='items'>
- /// Items to sort
- /// </param>
- /// <param name='configuration'>
- /// A configuration
- /// </param>
- /// <remarks>
- /// This methods sorts a collection of items, ensuring that every item is placed after all the items
- /// on which it depends.
- /// </remarks>
- public static ReadOnlyCollection<T> TopologicalSort<T> (IEnumerable<T> items, ConfigurationSelector configuration) where T: SolutionItem
- {
- IList<T> allItems;
- allItems = items as IList<T>;
- if (allItems == null)
- allItems = new List<T> (items);
-
- List<T> sortedEntries = new List<T> ();
- bool[] inserted = new bool[allItems.Count];
- bool[] triedToInsert = new bool[allItems.Count];
- for (int i = 0; i < allItems.Count; ++i) {
- if (!inserted[i])
- Insert<T> (i, allItems, sortedEntries, inserted, triedToInsert, configuration);
+ public virtual string[] SupportedPlatforms {
+ get {
+ return new string [0];
}
- return sortedEntries.AsReadOnly ();
}
- static void Insert<T> (int index, IList<T> allItems, List<T> sortedItems, bool[] inserted, bool[] triedToInsert, ConfigurationSelector solutionConfiguration) where T: SolutionItem
+ public virtual SolutionItemConfiguration GetConfiguration (ConfigurationSelector configuration)
{
- if (triedToInsert[index]) {
- throw new CyclicDependencyException ();
+ return (SolutionItemConfiguration) configuration.GetConfiguration (this) ?? DefaultConfiguration;
+ }
+
+ ItemConfiguration IConfigurationTarget.DefaultConfiguration {
+ get { return DefaultConfiguration; }
+ set { DefaultConfiguration = (SolutionItemConfiguration) value; }
+ }
+
+ public SolutionItemConfiguration DefaultConfiguration {
+ get {
+ if (activeConfiguration == null && configurations.Count > 0) {
+ return configurations[0];
+ }
+ return activeConfiguration;
}
- triedToInsert[index] = true;
- SolutionItem insertItem = allItems[index];
-
- foreach (SolutionItem reference in insertItem.GetReferencedItems (solutionConfiguration)) {
- for (int j=0; j < allItems.Count; ++j) {
- SolutionItem checkItem = allItems[j];
- if (reference == checkItem) {
- if (!inserted[j])
- Insert (j, allItems, sortedItems, inserted, triedToInsert, solutionConfiguration);
- break;
- }
+ set {
+ if (activeConfiguration != value) {
+ activeConfiguration = value;
+ NotifyModified ("DefaultConfiguration");
+ OnDefaultConfigurationChanged (new ConfigurationEventArgs (this, value));
}
}
- sortedItems.Add ((T)insertItem);
- inserted[index] = true;
}
- internal virtual IDictionary InternalGetExtendedProperties {
+ public string DefaultConfigurationId {
get {
- if (extendedProperties == null)
- extendedProperties = new Hashtable ();
- return extendedProperties;
+ if (DefaultConfiguration != null)
+ return DefaultConfiguration.Id;
+ else
+ return null;
+ }
+ set {
+ DefaultConfiguration = GetConfiguration (new ItemConfigurationSelector (value));
}
}
- void ILoadController.BeginLoad ()
+ public virtual ReadOnlyCollection<string> GetConfigurations ()
{
- loading++;
- OnBeginLoad ();
+ List<string> configs = new List<string> ();
+ foreach (SolutionItemConfiguration conf in Configurations)
+ configs.Add (conf.Id);
+ return configs.AsReadOnly ();
}
- void ILoadController.EndLoad ()
- {
- loading--;
- OnEndLoad ();
+ [ItemProperty ("Configurations")]
+ [ItemProperty ("Configuration", ValueType=typeof(SolutionItemConfiguration), Scope="*")]
+ public SolutionItemConfigurationCollection Configurations {
+ get {
+ return configurations;
+ }
}
- /// <summary>
- /// Called when a load operation for this solution item has started
- /// </summary>
- protected virtual void OnBeginLoad ()
- {
+ IItemConfigurationCollection IConfigurationTarget.Configurations {
+ get {
+ return Configurations;
+ }
}
- /// <summary>
- /// Called when a load operation for this solution item has finished
- /// </summary>
- protected virtual void OnEndLoad ()
+ public SolutionItemConfiguration AddNewConfiguration (string name)
{
+ SolutionItemConfiguration config = CreateConfiguration (name);
+ Configurations.Add (config);
+ return config;
}
- /// <summary>
- /// Notifies that this solution item has been modified
- /// </summary>
- /// <param name='hint'>
- /// Hint about which part of the solution item has been modified. This will typically be the property name.
- /// </param>
- internal protected void NotifyModified (string hint)
+ ItemConfiguration IConfigurationTarget.CreateConfiguration (string name)
{
- if (!Loading)
- ItemHandler.OnModified (hint);
- OnModified (new SolutionItemModifiedEventArgs (this, hint));
+ return CreateConfiguration (name);
}
-
- /// <summary>
- /// Raises the modified event.
- /// </summary>
- /// <param name='args'>
- /// Arguments.
- /// </param>
- protected virtual void OnModified (SolutionItemModifiedEventArgs args)
+
+ public virtual SolutionItemConfiguration CreateConfiguration (string name)
{
- if (Modified != null && !Disposed)
- Modified (this, args);
+ return ItemExtension.OnCreateConfiguration (name);
}
- /// <summary>
- /// Raises the name changed event.
- /// </summary>
- /// <param name='e'>
- /// Arguments.
- /// </param>
- protected virtual void OnNameChanged (SolutionItemRenamedEventArgs e)
+ void OnConfigurationAddedToCollection (object ob, ConfigurationEventArgs args)
{
- NotifyModified ("Name");
- if (NameChanged != null && !Disposed)
- NameChanged (this, e);
+ NotifyModified ("Configurations");
+ OnConfigurationAdded (new ConfigurationEventArgs (this, args.Configuration));
+ if (ConfigurationsChanged != null)
+ ConfigurationsChanged (this, EventArgs.Empty);
+ if (activeConfiguration == null)
+ DefaultConfigurationId = args.Configuration.Id;
}
- /// <summary>
- /// Initializes the item handler.
- /// </summary>
- /// <remarks>
- /// This method is called the first time an item handler is requested.
- /// Subclasses should override this method use SetItemHandler to
- /// assign a handler to this item.
- /// </remarks>
- protected virtual void InitializeItemHandler ()
+ void OnConfigurationRemovedFromCollection (object ob, ConfigurationEventArgs args)
{
+ if (activeConfiguration == args.Configuration) {
+ if (Configurations.Count > 0)
+ DefaultConfiguration = Configurations [0];
+ else
+ DefaultConfiguration = null;
+ }
+ NotifyModified ("Configurations");
+ OnConfigurationRemoved (new ConfigurationEventArgs (this, args.Configuration));
+ if (ConfigurationsChanged != null)
+ ConfigurationsChanged (this, EventArgs.Empty);
}
- /// <summary>
- /// Runs a build or execution target.
- /// </summary>
- /// <returns>
- /// The result of the operation
- /// </returns>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='target'>
- /// Name of the target
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to run the target
- /// </param>
- /// <remarks>
- /// Subclasses can override this method to provide a custom implementation of project operations such as
- /// build or clean. The default implementation delegates the execution to the more specific OnBuild
- /// and OnClean methods, or to the item handler for other targets.
- /// </remarks>
- internal protected virtual BuildResult OnRunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
+ public override StringTagModelDescription GetStringTagModelDescription (ConfigurationSelector conf)
{
- if (target == ProjectService.BuildTarget)
- return OnBuild (monitor, configuration);
- else if (target == ProjectService.CleanTarget) {
- OnClean (monitor, configuration);
- return new BuildResult ();
- }
- return ItemHandler.RunTarget (monitor, target, configuration) ?? new BuildResult ();
+ return ItemExtension.OnGetStringTagModelDescription (conf);
}
- /// <summary>
- /// Cleans the files produced by this solution item
- /// </summary>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to clean the project
- /// </param>
- protected abstract void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration);
+ StringTagModelDescription DoGetStringTagModelDescription (ConfigurationSelector conf)
+ {
+ StringTagModelDescription model = base.GetStringTagModelDescription (conf);
+ SolutionItemConfiguration config = GetConfiguration (conf);
+ if (config != null)
+ model.Add (config.GetType ());
+ else
+ model.Add (typeof(SolutionItemConfiguration));
+ return model;
+ }
+
+ public override StringTagModel GetStringTagModel (ConfigurationSelector conf)
+ {
+ return ItemExtension.OnGetStringTagModel (conf);
+ }
- /// <summary>
- /// Builds the solution item
- /// </summary>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to build the project
- /// </param>
- protected abstract BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration);
+ StringTagModel DoGetStringTagModel (ConfigurationSelector conf)
+ {
+ StringTagModel source = base.GetStringTagModel (conf);
+ SolutionItemConfiguration config = GetConfiguration (conf);
+ if (config != null)
+ source.Add (config);
+ return source;
+ }
+
+ internal protected override DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return ItemExtension.OnGetLastBuildTime (configuration);
+ }
+
+ DateTime DoGetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return base.OnGetLastBuildTime (configuration);
+ }
+
+ internal protected virtual void OnItemsAdded (IEnumerable<ProjectItem> objs)
+ {
+ ItemExtension.OnItemsAdded (objs);
+ }
- /// <summary>
- /// Executes this solution item
- /// </summary>
- /// <param name='monitor'>
- /// A progress monitor
- /// </param>
- /// <param name='context'>
- /// An execution context
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to execute the item
- /// </param>
- internal protected abstract void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration);
+ void DoOnItemsAdded (IEnumerable<ProjectItem> objs)
+ {
+ NotifyModified ("Items");
+ var args = new ProjectItemEventArgs ();
+ args.AddRange (objs.Select (pi => new ProjectItemEventInfo (this, pi)));
+ if (ProjectItemAdded != null)
+ ProjectItemAdded (this, args);
+ }
+
+ internal protected virtual void OnItemsRemoved (IEnumerable<ProjectItem> objs)
+ {
+ ItemExtension.OnItemsRemoved (objs);
+ }
- /// <summary>
- /// Checks if this solution item has modified files and has to be built
- /// </summary>
- /// <returns>
- /// <c>true</c> if the solution item has to be built
- /// </returns>
- /// <param name='configuration'>
- /// Configuration for which to do the check
- /// </param>
- internal protected virtual bool OnGetNeedsBuilding (ConfigurationSelector configuration)
+ void DoOnItemsRemoved (IEnumerable<ProjectItem> objs)
{
- return true;
+ NotifyModified ("Items");
+ var args = new ProjectItemEventArgs ();
+ args.AddRange (objs.Select (pi => new ProjectItemEventInfo (this, pi)));
+ if (ProjectItemRemoved != null)
+ ProjectItemRemoved (this, args);
+ }
+
+ protected virtual void OnDefaultConfigurationChanged (ConfigurationEventArgs args)
+ {
+ ItemExtension.OnDefaultConfigurationChanged (args);
}
- /// <summary>
- /// States whether this solution item needs to be built or not
- /// </summary>
- /// <param name='val'>
- /// Whether this solution item needs to be built or not
- /// </param>
- /// <param name='configuration'>
- /// Configuration for which to set the flag
- /// </param>
- internal protected virtual void OnSetNeedsBuilding (bool val, ConfigurationSelector configuration)
+ void DoOnDefaultConfigurationChanged (ConfigurationEventArgs args)
+ {
+ if (DefaultConfigurationChanged != null)
+ DefaultConfigurationChanged (this, args);
+ }
+
+ protected virtual void OnConfigurationAdded (ConfigurationEventArgs args)
{
+ ItemExtension.OnConfigurationAdded (args);
}
- /// <summary>
- /// Gets the time of the last build
- /// </summary>
- /// <returns>
- /// The last build time.
- /// </returns>
- /// <param name='configuration'>
- /// Configuration for which to get the last build time.
- /// </param>
- internal protected virtual DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
+ void DoOnConfigurationAdded (ConfigurationEventArgs args)
{
- return DateTime.MinValue;
+ if (ConfigurationAdded != null)
+ ConfigurationAdded (this, args);
+ }
+
+ protected virtual void OnConfigurationRemoved (ConfigurationEventArgs args)
+ {
+ ItemExtension.OnConfigurationRemoved (args);
}
- internal protected virtual bool OnGetSupportsTarget (string target)
+ void DoOnConfigurationRemoved (ConfigurationEventArgs args)
{
- return true;
+ if (ConfigurationRemoved != null)
+ ConfigurationRemoved (this, args);
}
- internal protected virtual bool OnGetSupportsExecute ()
+ protected virtual void OnReloadRequired (SolutionItemEventArgs args)
{
- return true;
+ ItemExtension.OnReloadRequired (args);
+ }
+
+ void DoOnReloadRequired (SolutionItemEventArgs args)
+ {
+ fileStatusTracker.FireReloadRequired (args);
}
- /// <summary>
- /// Determines whether this solution item can be executed using the specified context and configuration.
- /// </summary>
- /// <returns>
- /// <c>true</c> if this instance can be executed; otherwise, <c>false</c>.
- /// </returns>
- /// <param name='context'>
- /// An execution context
- /// </param>
- /// <param name='configuration'>
- /// Configuration to use to execute the item
- /// </param>
- internal protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ protected override void OnBoundToSolution ()
{
- return false;
+ ParentSolution.SolutionItemRemoved += HandleSolutionItemRemoved;
+ ParentSolution.SolutionItemAdded += HandleSolutionItemAdded;
+ ItemExtension.OnBoundToSolution ();
}
- internal protected virtual IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration)
+ void DoOnBoundToSolution ()
{
- yield break;
+ base.OnBoundToSolution ();
}
- protected virtual void OnBoundToSolution ()
+ protected override void OnUnboundFromSolution ()
{
+ ParentSolution.SolutionItemAdded -= HandleSolutionItemAdded;
+ ParentSolution.SolutionItemRemoved -= HandleSolutionItemRemoved;
+ ItemExtension.OnUnboundFromSolution ();
}
- internal protected virtual object OnGetService (Type t)
+ void DoOnUnboundFromSolution ()
{
- return ItemHandler.GetService (t);
+ base.OnUnboundFromSolution ();
}
- /// <summary>
- /// Occurs when the name of the item changes
- /// </summary>
- public event SolutionItemRenamedEventHandler NameChanged;
+
+ public event SolutionItemEventHandler Saved;
- /// <summary>
- /// Occurs when the item is modified.
- /// </summary>
- public event SolutionItemModifiedEventHandler Modified;
- }
+ class DefaultMSBuildItemExtension: SolutionItemExtension
+ {
+ internal protected override void OnInitializeFromTemplate (XmlElement template)
+ {
+ Item.OnInitializeFromTemplate (template);
+ }
+
+ internal protected override FilePath OnGetDefaultBaseDirectory ()
+ {
+ return Item.FileName.IsNullOrEmpty ? FilePath.Empty : Item.FileName.ParentDirectory;
+ }
+
+ internal protected override IEnumerable<SolutionItem> OnGetReferencedItems (ConfigurationSelector configuration)
+ {
+ return Item.OnGetReferencedItems (configuration);
+ }
+
+ internal protected override StringTagModelDescription OnGetStringTagModelDescription (ConfigurationSelector conf)
+ {
+ return Item.DoGetStringTagModelDescription (conf);
+ }
+
+ internal protected override StringTagModel OnGetStringTagModel (ConfigurationSelector conf)
+ {
+ return Item.DoGetStringTagModel (conf);
+ }
+
+ internal protected override bool OnGetSupportsFormat (FileFormat format)
+ {
+ return Item.OnGetSupportsFormat (format);
+ }
+
+ internal protected override IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
+ {
+ return Item.OnGetItemFiles (includeReferencedFiles);
+ }
+
+ internal protected override SolutionItemConfiguration OnCreateConfiguration (string name)
+ {
+ return new SolutionItemConfiguration (name);
+ }
+
+ internal protected override string[] SupportedPlatforms {
+ get {
+ return new string [0];
+ }
+ }
+
+ internal protected override DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return Item.DoGetLastBuildTime (configuration);
+ }
+
+ internal protected override Task OnLoad (ProgressMonitor monitor)
+ {
+ return Item.OnLoad (monitor);
+ }
+
+ internal protected override Task OnSave (ProgressMonitor monitor)
+ {
+ return Item.DoSave (monitor);
+ }
+
+ internal protected override bool OnSupportsBuild ()
+ {
+ return Item.OnGetSupportsBuild ();
+ }
+
+ internal protected override bool OnSupportsExecute ()
+ {
+ return Item.OnGetSupportsExecute ();
+ }
+
+ internal protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return Item.DoExecute (monitor, context, configuration);
+ }
+
+ internal protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return Item.DoGetCanExecute (context, configuration);
+ }
+
+ internal protected override IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration)
+ {
+ yield break;
+ }
+
+ internal protected override void OnExecutionTargetsChanged ()
+ {
+ Item.OnExecutionTargetsChanged ();
+ }
+
+ internal protected override void OnReloadRequired (SolutionItemEventArgs args)
+ {
+ Item.DoOnReloadRequired (args);
+ }
+
+ internal protected override void OnItemsAdded (IEnumerable<ProjectItem> objs)
+ {
+ Item.DoOnItemsAdded (objs);
+ }
+
+ internal protected override void OnItemsRemoved (IEnumerable<ProjectItem> objs)
+ {
+ Item.DoOnItemsRemoved (objs);
+ }
+
+ internal protected override void OnDefaultConfigurationChanged (ConfigurationEventArgs args)
+ {
+ Item.DoOnDefaultConfigurationChanged (args);
+ }
+
+ internal protected override void OnBoundToSolution ()
+ {
+ Item.DoOnBoundToSolution ();
+ }
+
+ internal protected override void OnUnboundFromSolution ()
+ {
+ Item.DoOnUnboundFromSolution ();
+ }
+
+ internal protected override void OnConfigurationAdded (ConfigurationEventArgs args)
+ {
+ Item.DoOnConfigurationAdded (args);
+ }
+
+ internal protected override void OnConfigurationRemoved (ConfigurationEventArgs args)
+ {
+ Item.DoOnConfigurationRemoved (args);
+ }
+
+ internal protected override void OnModified (SolutionItemModifiedEventArgs args)
+ {
+ Item.OnModified (args);
+ }
+
+ internal protected override void OnNameChanged (SolutionItemRenamedEventArgs e)
+ {
+ Item.OnNameChanged (e);
+ }
+
+ internal protected override IconId StockIcon {
+ get {
+ return "md-project";
+ }
+ }
+
+ internal protected override bool ItemFilesChanged {
+ get {
+ return Item.BaseItemFilesChanged;
+ }
+ }
+
+ internal protected override Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Item.OnBuild (monitor, configuration);
+ }
+
+ internal protected override Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return Item.OnClean (monitor, configuration);
+ }
+
+ internal protected override bool OnNeedsBuilding (ConfigurationSelector configuration)
+ {
+ return Item.OnGetNeedsBuilding (configuration);
+ }
+ }
+ }
+
[Mono.Addins.Extension]
class SolutionItemTagProvider: StringTagProvider<SolutionItem>, IStringTagProvider
{
@@ -1126,32 +1402,37 @@ namespace MonoDevelop.Projects
yield return new StringTagDescription ("AuthorCopyright", "Project Author Copyright");
yield return new StringTagDescription ("AuthorCompany", "Project Author Company");
yield return new StringTagDescription ("AuthorTrademark", "Project Trademark");
+ yield return new StringTagDescription ("ProjectFile", "Project File");
}
-
+
public override object GetTagValue (SolutionItem item, string tag)
{
switch (tag) {
- case "ITEMNAME":
- case "PROJECTNAME":
- return item.Name;
- case "AUTHORCOPYRIGHT":
- AuthorInformation authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Copyright;
- case "AUTHORCOMPANY":
- authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Company;
- case "AUTHORTRADEMARK":
- authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Trademark;
- case "AUTHOREMAIL":
- authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Email;
- case "AUTHORNAME":
- authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
- return authorInfo.Name;
- case "ITEMDIR":
- case "PROJECTDIR":
- return item.BaseDirectory;
+ case "ITEMNAME":
+ case "PROJECTNAME":
+ return item.Name;
+ case "AUTHORCOPYRIGHT":
+ AuthorInformation authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Copyright;
+ case "AUTHORCOMPANY":
+ authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Company;
+ case "AUTHORTRADEMARK":
+ authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Trademark;
+ case "AUTHOREMAIL":
+ authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Email;
+ case "AUTHORNAME":
+ authorInfo = item.AuthorInformation ?? AuthorInformation.Default;
+ return authorInfo.Name;
+ case "ITEMDIR":
+ case "PROJECTDIR":
+ return item.BaseDirectory;
+ case "ITEMFILE":
+ case "PROJECTFILE":
+ case "PROJECTFILENAME":
+ return item.FileName;
}
throw new NotSupportedException ();
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfiguration.cs
index 8ec16e80e2..49bdaaa7a0 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfiguration.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfiguration.cs
@@ -37,7 +37,7 @@ namespace MonoDevelop.Projects
[DataItem (FallbackType=typeof(UnknownConfiguration))]
public class SolutionItemConfiguration : ItemConfiguration
{
- SolutionEntityItem parentItem;
+ SolutionItem parentItem;
public SolutionItemConfiguration ()
{
@@ -47,7 +47,7 @@ namespace MonoDevelop.Projects
{
}
- public SolutionEntityItem ParentItem {
+ public SolutionItem ParentItem {
get { return parentItem; }
}
@@ -58,7 +58,7 @@ namespace MonoDevelop.Projects
?? configs.FirstOrDefault (c => Name == c.Name && (c.Platform == "" || c.Platform == "Any CPU"));
}
- internal void SetParentItem (SolutionEntityItem item)
+ internal void SetParentItem (SolutionItem item)
{
parentItem = item;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfigurationCollection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfigurationCollection.cs
index a470671b40..0e0a37dd06 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfigurationCollection.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemConfigurationCollection.cs
@@ -38,13 +38,13 @@ namespace MonoDevelop.Projects
{
public class SolutionItemConfigurationCollection : ItemConfigurationCollection<SolutionItemConfiguration>
{
- SolutionEntityItem parentItem;
+ SolutionItem parentItem;
public SolutionItemConfigurationCollection ()
{
}
- internal SolutionItemConfigurationCollection (SolutionEntityItem parentItem)
+ internal SolutionItemConfigurationCollection (SolutionItem parentItem)
{
this.parentItem = parentItem;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemEventArgs.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemEventArgs.cs
index d9b34ca114..0ca212bfdd 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemEventArgs.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemEventArgs.cs
@@ -36,10 +36,10 @@ namespace MonoDevelop.Projects
public class SolutionItemEventArgs : EventArgs
{
- SolutionItem entry;
+ SolutionFolderItem entry;
Solution solution;
- public SolutionItem SolutionItem {
+ public SolutionFolderItem SolutionItem {
get {
return entry;
}
@@ -51,12 +51,12 @@ namespace MonoDevelop.Projects
}
}
- public SolutionItemEventArgs (SolutionItem entry)
+ public SolutionItemEventArgs (SolutionFolderItem entry)
{
this.entry = entry;
}
- public SolutionItemEventArgs (SolutionItem entry, Solution solution)
+ public SolutionItemEventArgs (SolutionFolderItem entry, Solution solution)
{
this.solution = solution;
this.entry = entry;
@@ -69,7 +69,7 @@ namespace MonoDevelop.Projects
{
bool reloading;
- public SolutionItemChangeEventArgs (SolutionItem item, Solution parentSolution, bool reloading): base (item, parentSolution)
+ public SolutionItemChangeEventArgs (SolutionFolderItem item, Solution parentSolution, bool reloading): base (item, parentSolution)
{
this.reloading = reloading;
}
@@ -82,14 +82,14 @@ namespace MonoDevelop.Projects
/// When Reloading is true, it returns the original solution item that is being reloaded
/// </summary>
/// <value>The replaced item.</value>
- public SolutionItem ReplacedItem { get; internal set; }
+ public SolutionFolderItem ReplacedItem { get; internal set; }
}
public delegate void SolutionItemModifiedEventHandler (object sender, SolutionItemModifiedEventArgs e);
public class SolutionItemModifiedEventArgs: EventArgsChain<SolutionItemModifiedEventInfo>
{
- public SolutionItemModifiedEventArgs (SolutionItem item, string hint)
+ public SolutionItemModifiedEventArgs (SolutionFolderItem item, string hint)
{
Add (new SolutionItemModifiedEventInfo (item, hint));
}
@@ -99,7 +99,7 @@ namespace MonoDevelop.Projects
{
string hint;
- public SolutionItemModifiedEventInfo (SolutionItem item, string hint): base (item)
+ public SolutionItemModifiedEventInfo (SolutionFolderItem item, string hint): base (item)
{
this.hint = hint;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemExtension.cs
new file mode 100644
index 0000000000..cda42c19c3
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemExtension.cs
@@ -0,0 +1,289 @@
+//
+// SolutionItemExtension.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using MonoDevelop.Core;
+using MonoDevelop.Core.StringParsing;
+using MonoDevelop.Core.Execution;
+using System.Xml;
+using MonoDevelop.Projects.Formats.MSBuild;
+using MonoDevelop.Projects.Extensions;
+using System.Threading.Tasks;
+using System.Linq;
+
+namespace MonoDevelop.Projects
+{
+ public class SolutionItemExtension: WorkspaceObjectExtension, ILoadController
+ {
+ SolutionItemExtension next;
+
+ internal string FlavorGuid { get; set; }
+
+ internal protected override void InitializeChain (ChainedExtension next)
+ {
+ base.InitializeChain (next);
+ this.next = FindNextImplementation<SolutionItemExtension> (next);
+ }
+
+ internal protected override bool SupportsObject (WorkspaceObject item)
+ {
+ var p = item as SolutionItem;
+ if (p == null)
+ return false;
+
+ return FlavorGuid == null || p.GetItemTypeGuids ().Any (id => id.Equals (FlavorGuid, StringComparison.OrdinalIgnoreCase));
+ }
+
+ #region ILoadController implementation
+
+ void ILoadController.BeginLoad ()
+ {
+ OnBeginLoad ();
+ }
+
+ void ILoadController.EndLoad ()
+ {
+ OnEndLoad ();
+ }
+
+ #endregion
+
+ public SolutionItem Item {
+ get { return (SolutionItem) Owner; }
+ }
+
+ internal protected override void Initialize ()
+ {
+ base.Initialize ();
+ ProjectExtensionUtil.LoadControl (this);
+ }
+
+ internal protected virtual void OnInitializeNew (string languageName, ProjectCreateInformation info, XmlElement projectOptions)
+ {
+ next.OnInitializeNew (languageName, info, projectOptions);
+ }
+
+ internal protected virtual void OnInitializeFromTemplate (XmlElement template)
+ {
+ next.OnInitializeFromTemplate (template);
+ }
+
+ #region Project properties
+
+ internal protected virtual IconId StockIcon {
+ get {
+ return next.StockIcon;
+ }
+ }
+ #endregion
+
+ #region Project model
+
+ internal protected virtual FilePath OnGetDefaultBaseDirectory ()
+ {
+ return next.OnGetDefaultBaseDirectory ();
+ }
+
+ internal protected virtual IEnumerable<SolutionItem> OnGetReferencedItems (ConfigurationSelector configuration)
+ {
+ return next.OnGetReferencedItems (configuration);
+ }
+
+ internal protected virtual StringTagModelDescription OnGetStringTagModelDescription (ConfigurationSelector conf)
+ {
+ return next.OnGetStringTagModelDescription (conf);
+ }
+
+ internal protected virtual StringTagModel OnGetStringTagModel (ConfigurationSelector conf)
+ {
+ return next.OnGetStringTagModel (conf);
+ }
+
+ internal protected virtual bool OnGetSupportsFormat (FileFormat format)
+ {
+ return next.OnGetSupportsFormat (format);
+ }
+
+ internal protected virtual IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
+ {
+ return next.OnGetItemFiles (includeReferencedFiles);
+ }
+
+ internal protected virtual bool ItemFilesChanged {
+ get {
+ return next.ItemFilesChanged;
+ }
+ }
+
+ internal protected virtual SolutionItemConfiguration OnCreateConfiguration (string name)
+ {
+ return next.OnCreateConfiguration (name);
+ }
+
+ internal protected virtual string[] SupportedPlatforms {
+ get {
+ return next.SupportedPlatforms;
+ }
+ }
+
+ #endregion
+
+ #region Building
+
+ internal protected virtual bool OnSupportsBuild ()
+ {
+ return next.OnSupportsBuild ();
+ }
+
+ internal protected virtual bool OnSupportsExecute ()
+ {
+ return next.OnSupportsExecute ();
+ }
+
+ internal protected virtual Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return next.OnClean (monitor, configuration);
+ }
+
+ internal protected virtual bool OnNeedsBuilding (ConfigurationSelector configuration)
+ {
+ return next.OnNeedsBuilding (configuration);
+ }
+
+ internal protected virtual Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ return next.OnBuild (monitor, configuration);
+ }
+
+ internal protected virtual DateTime OnGetLastBuildTime (ConfigurationSelector configuration)
+ {
+ return next.OnGetLastBuildTime (configuration);
+ }
+
+ #endregion
+
+ #region Load / Save
+
+ internal protected virtual Task OnLoad (ProgressMonitor monitor)
+ {
+ return next.OnLoad (monitor);
+ }
+
+ internal protected virtual Task OnSave (ProgressMonitor monitor)
+ {
+ return next.OnSave (monitor);
+ }
+
+ protected virtual void OnBeginLoad ()
+ {
+ }
+
+ protected virtual void OnEndLoad ()
+ {
+ }
+
+ #endregion
+
+ #region Execution
+
+ internal protected virtual Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return next.OnExecute (monitor, context, configuration);
+ }
+
+ internal protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return next.OnGetCanExecute (context, configuration);
+ }
+
+ internal protected virtual IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration)
+ {
+ return next.OnGetExecutionTargets (configuration);
+ }
+
+ internal protected virtual void OnExecutionTargetsChanged ()
+ {
+ next.OnExecutionTargetsChanged ();
+ }
+
+ #endregion
+
+ #region Events
+
+ internal protected virtual void OnReloadRequired (SolutionItemEventArgs args)
+ {
+ next.OnReloadRequired (args);
+ }
+
+ internal protected virtual void OnItemsAdded (IEnumerable<ProjectItem> objs)
+ {
+ next.OnItemsAdded (objs);
+ }
+
+ internal protected virtual void OnItemsRemoved (IEnumerable<ProjectItem> objs)
+ {
+ next.OnItemsRemoved (objs);
+ }
+
+ internal protected virtual void OnDefaultConfigurationChanged (ConfigurationEventArgs args)
+ {
+ next.OnDefaultConfigurationChanged (args);
+ }
+
+ internal protected virtual void OnBoundToSolution ()
+ {
+ next.OnBoundToSolution ();
+ }
+
+ internal protected virtual void OnUnboundFromSolution ()
+ {
+ next.OnUnboundFromSolution ();
+ }
+
+ internal protected virtual void OnConfigurationAdded (ConfigurationEventArgs args)
+ {
+ next.OnConfigurationAdded (args);
+ }
+
+ internal protected virtual void OnConfigurationRemoved (ConfigurationEventArgs args)
+ {
+ next.OnConfigurationRemoved (args);
+ }
+
+ internal protected virtual void OnModified (SolutionItemModifiedEventArgs args)
+ {
+ next.OnModified (args);
+ }
+
+ internal protected virtual void OnNameChanged (SolutionItemRenamedEventArgs e)
+ {
+ next.OnNameChanged (e);
+ }
+
+ #endregion
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemFactory.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemFactory.cs
new file mode 100644
index 0000000000..9237ae7de1
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemFactory.cs
@@ -0,0 +1,36 @@
+//
+// SolutionItemFactory.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Threading.Tasks;
+
+namespace MonoDevelop.Projects
+{
+ public abstract class SolutionItemFactory
+ {
+ public abstract Task<SolutionItem> CreateItem (string fileName, string typeGuid);
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemReference.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemReference.cs
index d50f388d81..7abc72f987 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemReference.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemReference.cs
@@ -43,10 +43,10 @@ namespace MonoDevelop.Projects
{
}
- public SolutionItemReference (SolutionItem item)
+ public SolutionItemReference (SolutionFolderItem item)
{
- if (item is SolutionEntityItem) {
- path = ((SolutionEntityItem)item).FileName;
+ if (item is SolutionItem) {
+ path = ((SolutionItem)item).FileName;
} else {
path = item.ParentSolution.FileName;
if ((item is SolutionFolder) && ((SolutionFolder)item).IsRoot)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs
index 581d8a1b6a..e2142229bd 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs
@@ -1,4 +1,4 @@
-//
+//
// UnknownProject.cs
//
// Author:
@@ -26,33 +26,31 @@
using System;
using MonoDevelop.Core;
using System.Collections.Generic;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
public class UnknownProject: Project
{
- string loadError = string.Empty;
- bool unloaded;
-
// Store the file name locally to avoid the file format to change it
FilePath fileName;
public UnknownProject ()
{
+ IsUnsupportedProject = true;
NeedsReload = false;
- loadError = GettextCatalog.GetString ("Unknown project type");
}
public UnknownProject (FilePath file, string loadError): this ()
{
NeedsReload = false;
FileName = file;
- this.loadError = loadError;
+ UnsupportedProjectMessage = loadError;
}
- public override IEnumerable<string> GetProjectTypes ()
+ public override bool SupportsConfigurations ()
{
- yield return "";
+ return true;
}
public override FilePath FileName {
@@ -67,55 +65,36 @@ namespace MonoDevelop.Projects
}
}
-
- public string LoadError {
- get { return unloaded ? GettextCatalog.GetString ("Unavailable") : loadError; }
- set { loadError = value; }
- }
-
- public bool UnloadedEntry {
- get { return unloaded; }
- set { unloaded = value; }
- }
-
- public override string Name {
- get {
- if (!FileName.IsNullOrEmpty)
- return FileName.FileNameWithoutExtension;
- else
- return GettextCatalog.GetString ("Unknown entry");
- }
- set { }
+ protected override string OnGetName ()
+ {
+ if (!FileName.IsNullOrEmpty)
+ return FileName.FileNameWithoutExtension;
+ else
+ return GettextCatalog.GetString ("Unknown entry");
}
- internal protected override bool OnGetSupportsTarget (string target)
+ protected override bool OnGetSupportsTarget (string target)
{
// We can't do anything with unsupported projects, other than display them in the solution pad
return false;
}
- protected override void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected override Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
{
+ return Task.FromResult (BuildResult.Success);
}
- protected override BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected override Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
{
var r = new BuildResult ();
- r.AddError (loadError);
- return r;
- }
-
- protected internal override void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
- {
- }
-
- protected internal override bool OnGetNeedsBuilding (ConfigurationSelector configuration)
- {
- return false;
+ r.AddError (UnsupportedProjectMessage);
+ return Task.FromResult (r);
}
- protected internal override void OnSetNeedsBuilding (bool value, ConfigurationSelector configuration)
+ protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
{
+ return new Task (delegate {
+ });
}
public override SolutionItemConfiguration CreateConfiguration (string name)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownSolutionItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownSolutionItem.cs
index 08d8697279..9ab6a3102b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownSolutionItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownSolutionItem.cs
@@ -28,10 +28,11 @@
using System;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
- public class UnknownSolutionItem: SolutionEntityItem
+ public class UnknownSolutionItem: SolutionItem
{
string loadError = string.Empty;
bool unloaded;
@@ -41,7 +42,15 @@ namespace MonoDevelop.Projects
public UnknownSolutionItem ()
{
+ Initialize (this);
NeedsReload = false;
+ IsUnsupportedProject = true;
+ }
+
+ public override bool SupportsConfigurations ()
+ {
+ // The item is unknown, but we still want to read/write its configurations
+ return true;
}
public override FilePath FileName {
@@ -70,48 +79,30 @@ namespace MonoDevelop.Projects
loadError = GettextCatalog.GetString ("Unavailable");
}
}
-
- public override string Name {
- get {
- if (!FileName.IsNullOrEmpty)
- return FileName.FileNameWithoutExtension;
- else
- return GettextCatalog.GetString ("Unknown entry");
- }
- set { }
- }
- internal protected override bool OnGetSupportsTarget (string target)
+ protected override string OnGetName ()
{
- return false;
+ if (!FileName.IsNullOrEmpty)
+ return FileName.FileNameWithoutExtension;
+ else
+ return GettextCatalog.GetString ("Unknown entry");
}
-
- protected override void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration)
+
+ protected override Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration)
{
+ return Task.FromResult (BuildResult.Success);
}
- protected override BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
+ protected override Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration)
{
var r = new BuildResult ();
r.AddError ("Project unavailable");
- return r;
- }
-
- protected internal override void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
- {
- }
-
- protected internal override bool OnGetNeedsBuilding (ConfigurationSelector configuration)
- {
- return false;
- }
-
- protected internal override void OnSetNeedsBuilding (bool value, ConfigurationSelector configuration)
- {
+ return Task.FromResult (r);
}
- protected internal override void OnSave (IProgressMonitor monitor)
+ protected internal override Task OnSave (ProgressMonitor monitor)
{
+ return Task.FromResult (0);
}
}
@@ -119,6 +110,7 @@ namespace MonoDevelop.Projects
{
public UnloadedSolutionItem ()
{
+ Initialize (this);
UnloadedEntry = true;
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownWorkspaceItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownWorkspaceItem.cs
index a80b990f9c..3c598966a1 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownWorkspaceItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownWorkspaceItem.cs
@@ -27,6 +27,7 @@
using System;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
@@ -40,6 +41,7 @@ namespace MonoDevelop.Projects
public UnknownWorkspaceItem ()
{
NeedsReload = false;
+ Initialize (this);
}
public string LoadError {
@@ -52,19 +54,17 @@ namespace MonoDevelop.Projects
set { unloaded = value; }
}
- protected internal override void OnSave (IProgressMonitor monitor)
+ protected internal override Task OnSave (ProgressMonitor monitor)
{
- Services.ProjectService.InternalWriteWorkspaceItem (monitor, FileName, this);
+ return Services.ProjectService.InternalWriteWorkspaceItem (monitor, FileName, this);
}
- public override string Name {
- get {
- if (!FileName.IsNullOrEmpty)
- return FileName.FileNameWithoutExtension;
- else
- return GettextCatalog.GetString ("Unknown entry");
- }
- set { }
+ protected override string OnGetName ()
+ {
+ if (!FileName.IsNullOrEmpty)
+ return FileName.FileNameWithoutExtension;
+ else
+ return GettextCatalog.GetString ("Unknown entry");
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Workspace.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Workspace.cs
index a59cdab116..c75837c221 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Workspace.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Workspace.cs
@@ -33,13 +33,20 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using MonoDevelop.Core;
using MonoDevelop.Core.Serialization;
+using System.Linq;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
[ProjectModelDataItem]
- public class Workspace: WorkspaceItem, ICustomDataItem
+ public class Workspace: WorkspaceItem, ICustomDataItem, IBuildTarget
{
WorkspaceItemCollection items;
+
+ public Workspace ()
+ {
+ Initialize (this);
+ }
public override void Dispose ()
{
@@ -47,6 +54,37 @@ namespace MonoDevelop.Projects
foreach (WorkspaceItem it in Items)
it.Dispose ();
}
+
+ public async Task<BuildResult> Build (ProgressMonitor monitor, ConfigurationSelector configuration, bool buildReferencedTargets = false)
+ {
+ var res = new BuildResult { BuildCount = 0 };
+ foreach (var bt in Items.OfType<IBuildTarget> ())
+ res.Append (await bt.Build (monitor, configuration));
+ return res;
+ }
+
+ public async Task<BuildResult> Clean (ProgressMonitor monitor, ConfigurationSelector configuration)
+ {
+ var res = new BuildResult { BuildCount = 0 };
+ foreach (var bt in Items.OfType<IBuildTarget> ())
+ res.Append (await bt.Clean (monitor, configuration));
+ return res;
+ }
+
+ public Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
+ {
+ return false;
+ }
+
+ public bool NeedsBuilding (ConfigurationSelector configuration)
+ {
+ return Items.OfType<IBuildTarget> ().Any (t => t.NeedsBuilding (configuration));
+ }
public override ReadOnlyCollection<string> GetConfigurations ()
{
@@ -67,35 +105,12 @@ namespace MonoDevelop.Projects
return items;
}
}
-
- public override ReadOnlyCollection<T> GetAllItems<T> ()
- {
- List<T> list = new List<T> ();
- GetAllItems<T> (list, this);
- return list.AsReadOnly ();
- }
-
- void GetAllItems<T> (List<T> list, WorkspaceItem item) where T: WorkspaceItem
+
+ protected override IEnumerable<WorkspaceObject> OnGetChildren ()
{
- if (item is T)
- list.Add ((T) item);
-
- if (item is Workspace) {
- foreach (WorkspaceItem citem in ((Workspace)item).Items)
- GetAllItems<T> (list, citem);
- }
+ return Items;
}
- public override SolutionEntityItem FindSolutionItem (string fileName)
- {
- foreach (WorkspaceItem it in Items) {
- SolutionEntityItem si = it.FindSolutionItem (fileName);
- if (si != null)
- return si;
- }
- return null;
- }
-
[Obsolete("Use GetProjectsContainingFile() (plural) instead")]
public override Project GetProjectContainingFile (FilePath fileName)
{
@@ -116,7 +131,7 @@ namespace MonoDevelop.Projects
}
}
- public override bool ContainsItem (IWorkspaceObject obj)
+ public override bool ContainsItem (WorkspaceObject obj)
{
if (base.ContainsItem (obj))
return true;
@@ -129,53 +144,16 @@ namespace MonoDevelop.Projects
}
- public override ReadOnlyCollection<T> GetAllSolutionItems<T> ()
- {
- List<T> list = new List<T> ();
- foreach (WorkspaceItem it in Items) {
- list.AddRange (it.GetAllSolutionItems<T> ());
- }
- return list.AsReadOnly ();
- }
-
- public override void ConvertToFormat (FileFormat format, bool convertChildren)
+ public async override Task ConvertToFormat (FileFormat format, bool convertChildren)
{
- base.ConvertToFormat (format, convertChildren);
+ await base.ConvertToFormat (format, convertChildren);
if (convertChildren) {
foreach (WorkspaceItem it in Items)
- it.ConvertToFormat (format, true);
+ await it.ConvertToFormat (format, true);
}
}
-
- internal protected override BuildResult OnRunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
- {
- BuildResult result = null;
- monitor.BeginTask (null, Items.Count);
- try {
- foreach (WorkspaceItem it in Items) {
- BuildResult res = it.RunTarget (monitor, target, configuration);
- if (res != null) {
- if (result == null) {
- result = new BuildResult ();
- result.BuildCount = 0;
- }
- result.Append (res);
- }
- monitor.Step (1);
- }
- } finally {
- monitor.EndTask ();
- }
- return result;
- }
-
- protected internal override void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
- {
- throw new NotImplementedException ();
- }
-
- public WorkspaceItem ReloadItem (IProgressMonitor monitor, WorkspaceItem item)
+ public async Task<WorkspaceItem> ReloadItem (ProgressMonitor monitor, WorkspaceItem item)
{
if (Items.IndexOf (item) == -1)
throw new InvalidOperationException ("Item '" + item.Name + "' does not belong to workspace '" + Name + "'");
@@ -184,7 +162,7 @@ namespace MonoDevelop.Projects
WorkspaceItem newItem;
try {
- newItem = Services.ProjectService.ReadWorkspaceItem (monitor, item.FileName);
+ newItem = await Services.ProjectService.ReadWorkspaceItem (monitor, item.FileName);
} catch (Exception ex) {
UnknownWorkspaceItem e = new UnknownWorkspaceItem ();
e.LoadError = ex.Message;
@@ -203,9 +181,9 @@ namespace MonoDevelop.Projects
return newItem;
}
- public override List<FilePath> GetItemFiles (bool includeReferencedFiles)
+ protected override IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
{
- List<FilePath> list = base.GetItemFiles (includeReferencedFiles);
+ List<FilePath> list = base.OnGetItemFiles (includeReferencedFiles).ToList ();
if (includeReferencedFiles) {
foreach (WorkspaceItem it in Items)
list.AddRange (it.GetItemFiles (true));
@@ -271,20 +249,20 @@ namespace MonoDevelop.Projects
return data;
}
- void ICustomDataItem.Deserialize (ITypeSerializer handler, DataCollection data)
+ async void ICustomDataItem.Deserialize (ITypeSerializer handler, DataCollection data)
{
DataItem items = (DataItem) data.Extract ("Items");
handler.Deserialize (this, data);
- IProgressMonitor monitor = handler.SerializationContext.ProgressMonitor;
+ ProgressMonitor monitor = handler.SerializationContext.ProgressMonitor;
if (monitor == null)
- monitor = new MonoDevelop.Core.ProgressMonitoring.NullProgressMonitor ();
+ monitor = new ProgressMonitor ();
if (items != null) {
string baseDir = Path.GetDirectoryName (handler.SerializationContext.BaseFile);
monitor.BeginTask (null, items.ItemData.Count);
try {
foreach (DataValue item in items.ItemData) {
string file = Path.Combine (baseDir, item.Value);
- WorkspaceItem it = Services.ProjectService.ReadWorkspaceItem (monitor, file);
+ WorkspaceItem it = await Services.ProjectService.ReadWorkspaceItem (monitor, file);
if (it != null)
Items.Add (it);
monitor.Step (1);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs
index 8455a52481..d570d0792e 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs
@@ -41,15 +41,17 @@ using MonoDevelop.Core.Serialization;
using MonoDevelop.Core.StringParsing;
using MonoDevelop.Core.Execution;
using MonoDevelop.Projects.Extensions;
+using Mono.Addins;
+using System.Linq;
+using System.Threading.Tasks;
namespace MonoDevelop.Projects
{
- public abstract class WorkspaceItem : IBuildTarget, IWorkspaceFileObject, ILoadController
+ public abstract class WorkspaceItem : WorkspaceObject, IWorkspaceFileObject, ILoadController
{
Workspace parentWorkspace;
FileFormat format;
internal bool FormatSet;
- Hashtable extendedProperties;
FilePath fileName;
int loading;
PropertyBag userProperties;
@@ -57,17 +59,12 @@ namespace MonoDevelop.Projects
[ProjectPathItemProperty ("BaseDirectory", DefaultValue=null)]
FilePath baseDirectory;
-
+
public Workspace ParentWorkspace {
get { return parentWorkspace; }
- internal set { parentWorkspace = value; }
- }
-
- public IDictionary ExtendedProperties {
- get {
- if (extendedProperties == null)
- extendedProperties = new Hashtable ();
- return extendedProperties;
+ internal set {
+ parentWorkspace = value;
+ ParentObject = value;
}
}
@@ -80,12 +77,9 @@ namespace MonoDevelop.Projects
}
}
- public virtual string Name {
- get {
- if (fileName.IsNullOrEmpty)
- return string.Empty;
- else
- return fileName.FileNameWithoutExtension;
+ public new string Name {
+ get {
+ return base.Name;
}
set {
if (fileName.IsNullOrEmpty)
@@ -97,6 +91,14 @@ namespace MonoDevelop.Projects
}
}
}
+
+ protected override string OnGetName ()
+ {
+ if (fileName.IsNullOrEmpty)
+ return string.Empty;
+ else
+ return fileName.FileNameWithoutExtension;
+ }
public virtual FilePath FileName {
get {
@@ -124,12 +126,9 @@ namespace MonoDevelop.Projects
FileName = baseDirectory.Combine (name) + ".x";
}
- public FilePath BaseDirectory {
+ public new FilePath BaseDirectory {
get {
- if (baseDirectory.IsNull)
- return FileName.ParentDirectory.FullPath;
- else
- return baseDirectory;
+ return base.BaseDirectory;
}
set {
if (!value.IsNull && !FileName.IsNull && FileName.ParentDirectory.FullPath == value.FullPath)
@@ -141,82 +140,64 @@ namespace MonoDevelop.Projects
NotifyModified ();
}
}
+
+ protected override string OnGetBaseDirectory ()
+ {
+ if (baseDirectory.IsNull)
+ return FileName.ParentDirectory.FullPath;
+ else
+ return baseDirectory;
+ }
- public FilePath ItemDirectory {
- get { return FileName.ParentDirectory.FullPath; }
+ protected override string OnGetItemDirectory ()
+ {
+ return FileName.ParentDirectory.FullPath;
}
protected bool Loading {
get { return loading > 0; }
}
- public WorkspaceItem ()
+ protected WorkspaceItem ()
{
- MonoDevelop.Projects.Extensions.ProjectExtensionUtil.LoadControl (this);
+ ProjectExtensionUtil.LoadControl (this);
fileStatusTracker = new FileStatusTracker<WorkspaceItemEventArgs> (this, OnReloadRequired, new WorkspaceItemEventArgs (this));
+ Initialize (this);
}
- public T GetService<T> () where T: class
+ WorkspaceItemExtension itemExtension;
+
+ WorkspaceItemExtension ItemExtension {
+ get {
+ if (itemExtension == null)
+ itemExtension = ExtensionChain.GetExtension<WorkspaceItemExtension> ();
+ return itemExtension;
+ }
+ }
+
+ protected override IEnumerable<WorkspaceObjectExtension> CreateDefaultExtensions ()
{
- return (T) GetService (typeof(T));
+ yield return new DefaultWorkspaceItemExtension ();
}
-
- public virtual object GetService (Type t)
+
+ public IEnumerable<FilePath> GetItemFiles (bool includeReferencedFiles)
{
- return Services.ProjectService.GetExtensionChain (this).GetService (this, t);
+ return ItemExtension.GetItemFiles (includeReferencedFiles);
}
- public virtual List<FilePath> GetItemFiles (bool includeReferencedFiles)
- {
+ protected virtual IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles)
+ {
List<FilePath> col = FileFormat.Format.GetItemFiles (this);
if (!string.IsNullOrEmpty (FileName) && !col.Contains (FileName))
col.Add (FileName);
return col;
}
-
- public virtual SolutionEntityItem FindSolutionItem (string fileName)
- {
- return null;
- }
-
- public virtual bool ContainsItem (IWorkspaceObject obj)
+
+ public virtual bool ContainsItem (WorkspaceObject obj)
{
return this == obj;
}
- public ReadOnlyCollection<SolutionItem> GetAllSolutionItems ()
- {
- return GetAllSolutionItems<SolutionItem> ();
- }
-
- public virtual ReadOnlyCollection<T> GetAllSolutionItems<T> () where T: SolutionItem
- {
- return new List<T> ().AsReadOnly ();
- }
-
- public ReadOnlyCollection<Project> GetAllProjects ()
- {
- return GetAllSolutionItems<Project> ();
- }
-
- public virtual ReadOnlyCollection<Solution> GetAllSolutions ()
- {
- return GetAllItems<Solution> ();
- }
-
- public ReadOnlyCollection<WorkspaceItem> GetAllItems ()
- {
- return GetAllItems<WorkspaceItem> ();
- }
-
- public virtual ReadOnlyCollection<T> GetAllItems<T> () where T: WorkspaceItem
- {
- List<T> list = new List<T> ();
- if (this is T)
- list.Add ((T)this);
- return list.AsReadOnly ();
- }
-
[Obsolete("Use GetProjectsContainingFile() (plural) instead")]
public virtual Project GetProjectContainingFile (FilePath fileName)
{
@@ -232,119 +213,12 @@ namespace MonoDevelop.Projects
{
return new ReadOnlyCollection<string> (new string [0]);
}
-
- protected internal virtual void OnSave (IProgressMonitor monitor)
- {
- Services.ProjectService.InternalWriteWorkspaceItem (monitor, FileName, this);
- }
-
+
internal void SetParentWorkspace (Workspace workspace)
{
parentWorkspace = workspace;
}
-
- public BuildResult RunTarget (IProgressMonitor monitor, string target, string configuration)
- {
- return RunTarget (monitor, target, (SolutionConfigurationSelector) configuration);
- }
-
- public BuildResult RunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
- {
- return Services.ProjectService.GetExtensionChain (this).RunTarget (monitor, this, target, configuration);
- }
-
- public bool SupportsBuild ()
- {
- return SupportsTarget (ProjectService.BuildTarget);
- }
- public void Clean (IProgressMonitor monitor, string configuration)
- {
- Clean (monitor, (SolutionConfigurationSelector) configuration);
- }
-
- public void Clean (IProgressMonitor monitor, ConfigurationSelector configuration)
- {
- Services.ProjectService.GetExtensionChain (this).RunTarget (monitor, this, ProjectService.CleanTarget, configuration);
- }
-
- public bool SupportsTarget (string target)
- {
- return Services.ProjectService.GetExtensionChain (this).SupportsTarget (this, target);
- }
-
- public bool SupportsExecute ()
- {
- return Services.ProjectService.GetExtensionChain (this).SupportsExecute (this);
- }
-
- public BuildResult Build (IProgressMonitor monitor, string configuration)
- {
- return InternalBuild (monitor, (SolutionConfigurationSelector) configuration);
- }
-
- public BuildResult Build (IProgressMonitor monitor, ConfigurationSelector configuration)
- {
- return InternalBuild (monitor, configuration);
- }
-
- public void Execute (IProgressMonitor monitor, ExecutionContext context, string configuration)
- {
- Execute (monitor, context, (SolutionConfigurationSelector) configuration);
- }
-
- public void Execute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
- {
- Services.ProjectService.GetExtensionChain (this).Execute (monitor, this, context, configuration);
- }
-
- public bool CanExecute (ExecutionContext context, string configuration)
- {
- return CanExecute (context, (SolutionConfigurationSelector) configuration);
- }
-
- public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration)
- {
- return Services.ProjectService.GetExtensionChain (this).CanExecute (this, context, configuration);
- }
-
- public IEnumerable<ExecutionTarget> GetExecutionTargets (string configuration)
- {
- return GetExecutionTargets ((SolutionConfigurationSelector) configuration);
- }
-
- public IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration)
- {
- return Services.ProjectService.GetExtensionChain (this).GetExecutionTargets (this, configuration);
- }
-
- [Obsolete ("This method will be removed in future releases")]
- public bool NeedsBuilding (string configuration)
- {
- return true;
- }
-
- [Obsolete ("This method will be removed in future releases")]
- public bool NeedsBuilding (ConfigurationSelector configuration)
- {
- return true;
- }
-
- [Obsolete ("This method will be removed in future releases")]
- public void SetNeedsBuilding (bool value)
- {
- }
-
- [Obsolete ("This method will be removed in future releases")]
- public void SetNeedsBuilding (bool needsBuilding, string configuration)
- {
- }
-
- [Obsolete ("This method will be removed in future releases")]
- public void SetNeedsBuilding (bool needsBuilding, ConfigurationSelector configuration)
- {
- }
-
public virtual FileFormat FileFormat {
get {
if (format == null) {
@@ -359,17 +233,13 @@ namespace MonoDevelop.Projects
return true;
}
- public virtual void ConvertToFormat (FileFormat format, bool convertChildren)
+ public virtual Task ConvertToFormat (FileFormat format, bool convertChildren)
{
FormatSet = true;
this.format = format;
if (!string.IsNullOrEmpty (FileName))
FileName = format.GetValidFileName (this, FileName);
- }
-
- internal virtual BuildResult InternalBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
- {
- return Services.ProjectService.GetExtensionChain (this).RunTarget (monitor, this, ProjectService.BuildTarget, configuration);
+ return Task.FromResult (0);
}
protected virtual void OnConfigurationsChanged ()
@@ -380,17 +250,27 @@ namespace MonoDevelop.Projects
ParentWorkspace.OnConfigurationsChanged ();
}
- public void Save (FilePath fileName, IProgressMonitor monitor)
+ public void Save (FilePath fileName, ProgressMonitor monitor)
{
- FileName = fileName;
- Save (monitor);
+ SaveAsync (fileName, monitor).Wait ();
}
- public void Save (IProgressMonitor monitor)
+ public Task SaveAsync (FilePath fileName, ProgressMonitor monitor)
+ {
+ FileName = fileName;
+ return SaveAsync (monitor);
+ }
+
+ public void Save (ProgressMonitor monitor)
+ {
+ SaveAsync (monitor).Wait ();
+ }
+
+ public async Task SaveAsync (ProgressMonitor monitor)
{
try {
fileStatusTracker.BeginSave ();
- Services.ProjectService.GetExtensionChain (this).Save (monitor, this);
+ await ItemExtension.Save (monitor);
SaveUserProperties ();
OnSaved (new WorkspaceItemEventArgs (this));
@@ -400,7 +280,12 @@ namespace MonoDevelop.Projects
}
FileService.NotifyFileChanged (FileName);
}
-
+
+ protected internal virtual Task OnSave (ProgressMonitor monitor)
+ {
+ return Services.ProjectService.InternalWriteWorkspaceItem (monitor, FileName, this);
+ }
+
public virtual bool NeedsReload {
get {
return fileStatusTracker.NeedsReload;
@@ -416,59 +301,11 @@ namespace MonoDevelop.Projects
}
}
- internal protected virtual BuildResult OnRunTarget (IProgressMonitor monitor, string target, ConfigurationSelector configuration)
- {
- if (target == ProjectService.BuildTarget)
- return OnBuild (monitor, configuration);
- else if (target == ProjectService.CleanTarget) {
- OnClean (monitor, configuration);
- return null;
- }
- return null;
- }
-
- internal protected virtual bool OnGetSupportsTarget (string target)
- {
- return true;
- }
-
internal protected virtual bool OnGetSupportsExecute ()
{
return true;
}
- protected virtual void OnClean (IProgressMonitor monitor, ConfigurationSelector configuration)
- {
- }
-
- protected virtual BuildResult OnBuild (IProgressMonitor monitor, ConfigurationSelector configuration)
- {
- return null;
- }
-
- internal protected virtual void OnExecute (IProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
- {
- }
-
- internal protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration)
- {
- return true;
- }
-
- internal protected virtual IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration)
- {
- yield break;
- }
-
- internal protected virtual bool OnGetNeedsBuilding (ConfigurationSelector configuration)
- {
- return true;
- }
-
- internal protected virtual void OnSetNeedsBuilding (bool val, ConfigurationSelector configuration)
- {
- }
-
void ILoadController.BeginLoad ()
{
loading++;
@@ -571,15 +408,9 @@ namespace MonoDevelop.Projects
return absPath.ToRelative (BaseDirectory);
}
- public virtual void Dispose()
+ public override void Dispose()
{
- if (extendedProperties != null) {
- foreach (object ob in extendedProperties.Values) {
- IDisposable disp = ob as IDisposable;
- if (disp != null)
- disp.Dispose ();
- }
- }
+ base.Dispose ();
if (userProperties != null)
userProperties.Dispose ();
}
@@ -592,11 +423,6 @@ namespace MonoDevelop.Projects
NameChanged (this, e);
}
- internal protected virtual object OnGetService (Type t)
- {
- return null;
- }
-
protected void NotifyModified ()
{
OnModified (new WorkspaceItemEventArgs (this));
@@ -632,6 +458,19 @@ namespace MonoDevelop.Projects
fileStatusTracker.ReloadRequired -= value;
}
}*/
+
+ internal class DefaultWorkspaceItemExtension: WorkspaceItemExtension
+ {
+ internal protected override IEnumerable<FilePath> GetItemFiles (bool includeReferencedFiles)
+ {
+ return Item.OnGetItemFiles (includeReferencedFiles);
+ }
+
+ internal protected override Task Save (ProgressMonitor monitor)
+ {
+ return Item.OnSave (monitor);
+ }
+ }
}
class FileStatusTracker<TEventArgs> where TEventArgs:EventArgs
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItemExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItemExtension.cs
new file mode 100644
index 0000000000..5d3d7643ac
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItemExtension.cs
@@ -0,0 +1,67 @@
+//
+// WorkspaceItemExtension.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using MonoDevelop.Core;
+using System.Threading.Tasks;
+
+namespace MonoDevelop.Projects
+{
+ public class WorkspaceItemExtension: WorkspaceObjectExtension
+ {
+ WorkspaceItemExtension next;
+
+ internal protected override bool SupportsObject (WorkspaceObject item)
+ {
+ return item is WorkspaceItem;
+ }
+
+ internal protected override void InitializeChain (ChainedExtension next)
+ {
+ this.next = FindNextImplementation<WorkspaceItemExtension> (next);
+ }
+
+ protected WorkspaceItem Item {
+ get { return (WorkspaceItem) base.Owner; }
+ }
+
+ internal protected virtual bool SupportsItem (WorkspaceItem item)
+ {
+ return next.SupportsItem (item);
+ }
+
+ internal protected virtual Task Save (ProgressMonitor monitor)
+ {
+ return next.Save (monitor);
+ }
+
+ internal protected virtual IEnumerable<FilePath> GetItemFiles (bool includeReferencedFiles)
+ {
+ return next.GetItemFiles (includeReferencedFiles);
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs
new file mode 100644
index 0000000000..ec464b7769
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObject.cs
@@ -0,0 +1,303 @@
+// IWorkspaceObject.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@novell.com>
+//
+// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//
+
+using System;
+using System.Collections.Generic;
+using MonoDevelop.Core;
+using MonoDevelop.Core.Serialization;
+using System.Collections;
+using MonoDevelop.Projects.Extensions;
+using Mono.Addins;
+using System.Linq;
+using System.Threading.Tasks;
+
+
+namespace MonoDevelop.Projects
+{
+ public abstract class WorkspaceObject: IExtendedDataItem, IFolderItem, IDisposable
+ {
+ Hashtable extendedProperties;
+ bool initializeCalled;
+
+ protected void Initialize<T> (T instance)
+ {
+ if (instance.GetType () != typeof(T))
+ return;
+ initializeCalled = true;
+ OnInitialize ();
+ InitializeExtensionChain ();
+ OnExtensionChainInitialized ();
+ }
+
+ public string Name {
+ get { return OnGetName (); }
+ }
+
+ public FilePath ItemDirectory {
+ get { return OnGetItemDirectory (); }
+ }
+
+ public FilePath BaseDirectory {
+ get { return OnGetBaseDirectory (); }
+ }
+
+ public WorkspaceObject ParentObject { get; protected set; }
+
+ public IEnumerable<WorkspaceObject> GetChildren ()
+ {
+ return OnGetChildren ();
+ }
+
+ public IEnumerable<T> GetAllItems<T> () where T: WorkspaceObject
+ {
+ if (this is T)
+ yield return (T)this;
+ foreach (var c in OnGetChildren ()) {
+ foreach (var r in c.GetAllItems<T> ())
+ yield return r;
+ }
+ }
+
+ /// <summary>
+ /// Gets extended properties.
+ /// </summary>
+ /// <remarks>
+ /// This dictionary can be used by add-ins to store arbitrary information about this solution item.
+ /// Keys and values can be of any type.
+ /// If a value implements IDisposable, the value will be disposed when this item is disposed.
+ /// </remarks>
+ public IDictionary ExtendedProperties {
+ get {
+ return OnGetExtendedProperties ();
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this <see cref="MonoDevelop.Projects.SolutionItem"/> has been disposed.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if disposed; otherwise, <c>false</c>.
+ /// </value>
+ internal protected bool Disposed { get; private set; }
+
+ public virtual void Dispose ()
+ {
+ if (Disposed)
+ return;
+
+ Disposed = true;
+
+ if (extensionChain != null) {
+ extensionChain.Dispose ();
+ extensionChain = null;
+ }
+
+ if (extendedProperties != null) {
+ foreach (object ob in extendedProperties.Values) {
+ IDisposable disp = ob as IDisposable;
+ if (disp != null)
+ disp.Dispose ();
+ }
+ extendedProperties = null;
+ }
+ }
+
+ /// <summary>
+ /// Gets a service instance of a given type
+ /// </summary>
+ /// <returns>
+ /// The service.
+ /// </returns>
+ /// <typeparam name='T'>
+ /// Type of the service
+ /// </typeparam>
+ /// <remarks>
+ /// This method looks for an imlpementation of a service of the given type.
+ /// </remarks>
+ public T GetService<T> ()
+ {
+ return (T) GetService (typeof(T));
+ }
+
+ /// <summary>
+ /// Gets a service instance of a given type
+ /// </summary>
+ /// <returns>
+ /// The service.
+ /// </returns>
+ /// <param name='t'>
+ /// Type of the service
+ /// </param>
+ /// <remarks>
+ /// This method looks for an imlpementation of a service of the given type.
+ /// </remarks>
+ public object GetService (Type t)
+ {
+ return ItemExtension.GetService (t);
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the extension chain for this object has already been created and initialized
+ /// </summary>
+ protected bool IsExtensionChainCreated {
+ get { return extensionChain != null; }
+ }
+
+ ExtensionChain extensionChain;
+ protected ExtensionChain ExtensionChain {
+ get {
+ if (extensionChain == null) {
+ if (!initializeCalled)
+ throw new InvalidOperationException ("The constructor of type " + GetType () + " must call Initialize(this)");
+ else
+ throw new InvalidOperationException ("The extension chain can't be used before OnExtensionChainInitialized() method is called");
+ }
+ return extensionChain;
+ }
+ }
+
+ WorkspaceObjectExtension itemExtension;
+
+ WorkspaceObjectExtension ItemExtension {
+ get {
+ if (itemExtension == null)
+ itemExtension = ExtensionChain.GetExtension<WorkspaceObjectExtension> ();
+ return itemExtension;
+ }
+ }
+
+ void InitializeExtensionChain ()
+ {
+ // Create an initial empty extension chain. This avoid crashes in case a call to SupportsObject ends
+ // calling methods from the extension
+
+ var tempExtensions = new List<WorkspaceObjectExtension> ();
+ tempExtensions.AddRange (CreateDefaultExtensions ().Reverse ());
+ extensionChain = ExtensionChain.Create (tempExtensions.ToArray ());
+ foreach (var e in tempExtensions)
+ e.Init (this);
+
+ // Collect extensions that support this object
+
+ var extensions = new List<WorkspaceObjectExtension> ();
+ foreach (ProjectModelExtensionNode node in AddinManager.GetExtensionNodes (ProjectService.ProjectModelExtensionsPath)) {
+ if (node.CanHandleObject (this)) {
+ var ext = node.CreateExtension ();
+ if (ext.SupportsObject (this))
+ extensions.Add (ext);
+ else
+ ext.Dispose ();
+ }
+ }
+
+ foreach (var e in tempExtensions)
+ e.Dispose ();
+
+ // Now create the final extension chain
+
+ extensions.Reverse ();
+ extensions.AddRange (CreateDefaultExtensions ().Reverse ());
+ extensionChain = ExtensionChain.Create (extensions.ToArray ());
+ foreach (var e in extensions)
+ e.Init (this);
+ }
+
+ protected virtual IEnumerable<WorkspaceObjectExtension> CreateDefaultExtensions ()
+ {
+ yield return new DefaultWorkspaceObjectExtension ();
+ }
+
+ /// <summary>
+ /// Called after the object is created, but before the extension chain has been created.
+ /// </summary>
+ protected virtual void OnInitialize ()
+ {
+ }
+
+ /// <summary>
+ /// Called when the extension chain for this object has been created. This method can be overriden
+ /// to do initializations on the object that require access to the extension chain
+ /// </summary>
+ protected virtual void OnExtensionChainInitialized ()
+ {
+ }
+
+ protected virtual IDictionary OnGetExtendedProperties ()
+ {
+ if (extendedProperties == null)
+ extendedProperties = new Hashtable ();
+ return extendedProperties;
+ }
+
+ protected virtual IEnumerable<WorkspaceObject> OnGetChildren ()
+ {
+ yield break;
+ }
+
+ protected virtual object OnGetService (Type t)
+ {
+ return t.IsInstanceOfType (this) ? this : null;
+ }
+
+ protected abstract string OnGetName ();
+
+ protected abstract string OnGetItemDirectory ();
+
+ protected abstract string OnGetBaseDirectory ();
+
+ internal class DefaultWorkspaceObjectExtension: WorkspaceObjectExtension
+ {
+ internal protected override object GetService (Type t)
+ {
+ return Owner.OnGetService (t);
+ }
+ }
+ }
+
+ public static class WorkspaceObjectExtensions
+ {
+ public static T As<T> (this WorkspaceObject ob) where T:class
+ {
+ return ob != null ? ob.GetService<T> () : null;
+ }
+ }
+
+ public interface IWorkspaceFileObject: IFileItem, IDisposable
+ {
+ FileFormat FileFormat { get; }
+ Task ConvertToFormat (FileFormat format, bool convertChildren);
+ bool SupportsFormat (FileFormat format);
+ IEnumerable<FilePath> GetItemFiles (bool includeReferencedFiles);
+ new FilePath FileName { get; set; }
+ bool NeedsReload { get; set; }
+ bool ItemFilesChanged { get; }
+ Task SaveAsync (ProgressMonitor monitor);
+ string Name { get; set; }
+ FilePath BaseDirectory { get; }
+ FilePath ItemDirectory { get; }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProjectBinding.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectExtension.cs
index 4ec770d696..541c25ad7c 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/PortableDotNetProjectBinding.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectExtension.cs
@@ -1,20 +1,21 @@
-//
-// PortableDotNetProjectBinding.cs
-//
-// Author: Jeffrey Stedfast <jeff@xamarin.com>
-//
-// Copyright (c) 2012 Xamarin Inc.
-//
+//
+// WorkspaceObjectExtension.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
-//
+//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -22,36 +23,41 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-
using System;
-using System.IO;
-using System.Xml;
-using MonoDevelop.Core.Serialization;
-using MonoDevelop.Core;
+using Mono.Addins;
namespace MonoDevelop.Projects
{
- public class PortableDotNetProjectBinding : IProjectBinding
+ public class WorkspaceObjectExtension: ChainedExtension
{
- public string Name {
- get { return "PortableDotNet"; }
+ WorkspaceObjectExtension next;
+
+ internal protected override void InitializeChain (ChainedExtension next)
+ {
+ this.next = FindNextImplementation<WorkspaceObjectExtension> (next);
}
-
- public Project CreateProject (ProjectCreateInformation info, System.Xml.XmlElement projectOptions)
+
+ protected WorkspaceObject Owner { get; private set; }
+
+ internal protected virtual bool SupportsObject (WorkspaceObject item)
{
- string languageName = projectOptions.GetAttribute ("language");
-
- return new PortableDotNetProject (languageName, info, projectOptions);
+ return true;
}
-
- public Project CreateSingleFileProject (string sourceFile)
+
+ internal void Init (WorkspaceObject item)
{
- throw new InvalidOperationException ();
+ Owner = item;
+ Initialize ();
}
-
- public bool CanCreateSingleFileProject (string sourceFile)
+
+ internal protected virtual void Initialize ()
{
- return false;
+ }
+
+ internal protected virtual object GetService (Type t)
+ {
+ return t.IsInstanceOfType (this) ? this : next.GetService (t);
}
}
}
+