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:
authorLluis Sanchez Gual <lluis@xamarin.com>2015-04-15 21:25:21 +0300
committerLluis Sanchez Gual <lluis@xamarin.com>2015-04-15 22:01:36 +0300
commitc01e9a973783cda83d6f6aa702842c6438050bc4 (patch)
treef0168bc741c06b980e61ef9dd7100756cae73bb4 /main/src/core
parent4d8e96a1003ead9b3ce76b1c71602795d031eedb (diff)
Fix unsupported project loading
Properly load unsupported projects as UnknownProject, and support saving simple changes such as adding/removing files.
Diffstat (limited to 'main/src/core')
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs22
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs18
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs122
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/SlnFileFormat.cs55
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs21
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs6
7 files changed, 130 insertions, 117 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs
index 186bbcd097..140f09a6b9 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs
@@ -24,6 +24,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
+using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using MonoDevelop.Projects.Formats.MSBuild;
@@ -46,6 +47,7 @@ namespace MonoDevelop.Projects.Extensions
public override async Task<SolutionItem> CreateSolutionItem (ProgressMonitor monitor, string fileName)
{
MSBuildProject p = null;
+ Project project = null;
if (!string.IsNullOrEmpty (fileName)) {
p = await MSBuildProject.LoadAsync (fileName);
@@ -53,24 +55,26 @@ namespace MonoDevelop.Projects.Extensions
if (migrators.Count > 0)
await MSBuildProjectService.MigrateFlavors (monitor, fileName, Guid, p, migrators);
+ var unsupporedFlavor = p.ProjectTypeGuids.FirstOrDefault (fid => !MSBuildProjectService.IsKnownFlavorGuid (fid) && !MSBuildProjectService.IsKnownTypeGuid (fid));
+ if (unsupporedFlavor != null) {
+ // The project has a flavor that's not supported. Return a fake project (if possible).
+ return MSBuildProjectService.CreateUnknownSolutionItem (monitor, fileName, Guid, unsupporedFlavor, null);
+ }
+
if (MSBuildSupport == MSBuildSupport.NotSupported || MSBuildProjectService.GetMSBuildSupportForFlavors (p.ProjectTypeGuids) == MSBuildSupport.NotSupported)
p.UseMSBuildEngine = false;
// Evaluate the project now. If evaluation fails an exception will be thrown, and when that
// happens the solution will create a placeholder project.
- try {
- p.Evaluate ();
- } catch (ProjectEvaluationException ex) {
- if (p.UseMSBuildEngine) {
- p.UseMSBuildEngine = false;
- p.Evaluate ();
- }
- }
+ p.Evaluate ();
}
- var project = await base.CreateSolutionItem (monitor, fileName) as Project;
+ if (project == null)
+ project = await base.CreateSolutionItem (monitor, fileName) as Project;
+
if (project == null)
throw new InvalidOperationException ("Project node type is not a subclass of MonoDevelop.Projects.Project");
+
if (p != null)
project.SetCreationContext (Project.CreationContext.Create (p, Guid));
return project;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs
index b413e0bc69..7757b02041 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs
@@ -109,21 +109,9 @@ namespace MonoDevelop.Projects.Extensions
if (factory == null)
factory = (SolutionItemFactory)Activator.CreateInstance (ItemType);
item = await factory.CreateItem (fileName, Guid);
- } else {
- try {
- // Some subclasses (such as ProjectTypeNode) need to assign some data to
- // the object before it is initialized. However, by default initialization
- // is automatically made by the constructor, so to support this scenario
- // the initialization has to be delayed. This is done by setting the
- // MonoDevelop.DelayItemInitialization logical context property.
- // When this property is set, the object is not initialized, and it has
- // to be manually initialized by calling EnsureInitialized.
- CallContext.LogicalSetData ("MonoDevelop.DelayItemInitialization", true);
- item = (SolutionItem)Activator.CreateInstance (ItemType, true);
- } finally {
- CallContext.LogicalSetData ("MonoDevelop.DelayItemInitialization", false);
- }
- }
+ } else
+ item = MSBuildProjectService.CreateUninitializedInstance (ItemType);
+
item.TypeGuid = Guid;
return item;
}
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 447003f2a6..754d059e46 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
@@ -129,34 +129,36 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return target;
return null;
}
-
+
+ /// <summary>
+ /// Loads a solution item
+ /// </summary>
+ /// <returns>The item.</returns>
+ /// <param name="monitor">Progress monitor</param>
+ /// <param name="fileName">File path to the item file</param>
+ /// <param name="expectedFormat">File format that the project should have</param>
+ /// <param name="typeGuid">Optional item type GUID. If not provided, the type is guessed from the file extension.</param>
+ /// <param name="itemGuid">Optional item Id</param>
+ /// <param name="ctx">Optional solution context</param>
public async static Task<SolutionItem> LoadItem (ProgressMonitor monitor, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid, SolutionLoadContext ctx)
{
- foreach (SolutionItemTypeNode node in GetItemTypeNodes ()) {
- if (node.CanHandleFile (fileName, typeGuid))
- return await LoadProjectAsync (monitor, fileName, expectedFormat, null, node, ctx);
- }
-
- // 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 p = (UnknownProject) await LoadProjectAsync (monitor, fileName, expectedFormat, typeof(UnknownProject), null, ctx);
- p.UnsupportedProjectMessage = projectInfo.GetInstructions ();
- return p;
- }
- return null;
- }
+ SolutionItem item = null;
- internal static async Task<SolutionItem> LoadProjectAsync (ProgressMonitor monitor, string fileName, MSBuildFileFormat format, Type itemType, SolutionItemTypeNode node, SolutionLoadContext ctx)
- {
- SolutionItem item;
+ // Find an extension node that can handle this item type
+ var node = GetItemTypeNodes ().FirstOrDefault (n => n.CanHandleFile (fileName, typeGuid));
- if (itemType != null)
- item = (SolutionItem)Activator.CreateInstance (itemType);
- else
+ if (node != null) {
item = await node.CreateSolutionItem (monitor, fileName);
+ if (item == null)
+ return null;
+ }
+
+ if (item == null) {
+ // If it is a known unsupported project, load it as UnknownProject
+ item = CreateUnknownSolutionItem (monitor, fileName, typeGuid, typeGuid, ctx);
+ if (item == null)
+ return null;
+ }
item.EnsureInitialized ();
@@ -166,10 +168,69 @@ namespace MonoDevelop.Projects.Formats.MSBuild
item.NotifyItemReady ();
};
- await item.LoadAsync (monitor, fileName, format);
+ await item.LoadAsync (monitor, fileName, expectedFormat);
return item;
}
+ internal static SolutionItem CreateUnknownSolutionItem (ProgressMonitor monitor, string fileName, string typeGuid, string unknownTypeGuid, SolutionLoadContext ctx)
+ {
+ bool loadAsProject = false;
+ string unsupportedMessage;
+
+ var relPath = ctx != null && ctx.Solution != null ? new FilePath (fileName).ToRelative (ctx.Solution.BaseDirectory).ToString() : new FilePath (fileName).FileName;
+ var guids = !string.IsNullOrEmpty (unknownTypeGuid) ? unknownTypeGuid.Split (new char[] {';'}, StringSplitOptions.RemoveEmptyEntries) : new string[0];
+
+ if (!string.IsNullOrEmpty (unknownTypeGuid)) {
+ var projectInfo = MSBuildProjectService.GetUnknownProjectTypeInfo (guids, fileName);
+ if (projectInfo != null) {
+ loadAsProject = projectInfo.LoadFiles;
+ unsupportedMessage = projectInfo.GetInstructions ();
+ LoggingService.LogWarning (string.Format ("Could not load {0} project '{1}'. {2}", projectInfo.Name, relPath, projectInfo.GetInstructions ()));
+ monitor.ReportWarning (GettextCatalog.GetString ("Could not load {0} project '{1}'. {2}", projectInfo.Name, relPath, projectInfo.GetInstructions ()));
+ } else {
+ unsupportedMessage = GettextCatalog.GetString ("Unknown project type: {0}", unknownTypeGuid);
+ LoggingService.LogWarning (string.Format ("Could not load project '{0}' with unknown item type '{1}'", relPath, unknownTypeGuid));
+ monitor.ReportWarning (GettextCatalog.GetString ("Could not load project '{0}' with unknown item type '{1}'", relPath, unknownTypeGuid));
+ return null;
+ }
+ } else {
+ unsupportedMessage = GettextCatalog.GetString ("Unknown project type");
+ LoggingService.LogWarning (string.Format ("Could not load project '{0}' with unknown item type", relPath));
+ monitor.ReportWarning (GettextCatalog.GetString ("Could not load project '{0}' with unknown item type", relPath));
+ }
+ if (loadAsProject) {
+ var project = (Project) CreateUninitializedInstance (typeof(UnknownProject));
+ project.UnsupportedProjectMessage = unsupportedMessage;
+ project.SetCreationContext (Project.CreationContext.Create (typeGuid, new string[0]));
+ return project;
+ } else
+ return null;
+ }
+
+
+ /// <summary>
+ /// Creates an uninitialized solution item instance
+ /// </summary>
+ /// <param name="type">Solution item type</param>
+ /// <remarks>
+ /// Some subclasses (such as ProjectTypeNode) need to assign some data to
+ /// the object before it is initialized. However, by default initialization
+ /// is automatically made by the constructor, so to support this scenario
+ /// the initialization has to be delayed. This is done by setting the
+ /// MonoDevelop.DelayItemInitialization logical context property.
+ /// When this property is set, the object is not initialized, and it has
+ /// to be manually initialized by calling EnsureInitialized.
+ /// </remarks>
+ internal static SolutionItem CreateUninitializedInstance (Type type)
+ {
+ try {
+ System.Runtime.Remoting.Messaging.CallContext.LogicalSetData ("MonoDevelop.DelayItemInitialization", true);
+ return (SolutionItem)Activator.CreateInstance (type, true);
+ } finally {
+ System.Runtime.Remoting.Messaging.CallContext.LogicalSetData ("MonoDevelop.DelayItemInitialization", false);
+ }
+ }
+
internal static bool CanCreateSolutionItem (string type, ProjectCreateInformation info, System.Xml.XmlElement projectOptions)
{
foreach (var node in GetItemTypeNodes ()) {
@@ -211,7 +272,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
if (node != null) {
if (node.MSBuildSupport != MSBuildSupport.Supported)
return node.MSBuildSupport;
- } else
+ } else if (!IsKnownTypeGuid (fid))
throw new UnknownSolutionItemTypeException (fid);
}
return MSBuildSupport.Supported;
@@ -308,6 +369,11 @@ namespace MonoDevelop.Projects.Formats.MSBuild
throw new InvalidOperationException ("Language not supported: " + guid);
}
+ internal static bool IsKnownFlavorGuid (string guid)
+ {
+ return WorkspaceObject.GetModelExtensions (null).OfType<SolutionItemExtensionNode> ().Any (n => n.Guid.Equals (guid, StringComparison.InvariantCultureIgnoreCase));
+ }
+
internal static bool IsKnownTypeGuid (string guid)
{
foreach (var node in GetItemTypeNodes ()) {
@@ -399,6 +465,9 @@ namespace MonoDevelop.Projects.Formats.MSBuild
internal static MSBuildSupport GetMSBuildSupportForProject (Project project)
{
+ if (project is UnknownProject)
+ return MSBuildSupport.NotSupported;
+
foreach (var node in GetItemTypeNodes ().OfType<ProjectTypeNode> ()) {
if (node.Guid.Equals (project.TypeGuid, StringComparison.OrdinalIgnoreCase)) {
if (node.MSBuildSupport != MSBuildSupport.Supported)
@@ -406,8 +475,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild
return GetMSBuildSupportForFlavors (project.FlavorGuids);
}
}
- // The generic handler should always be found
- throw new InvalidOperationException ();
+ return MSBuildSupport.NotSupported;
}
public static void RegisterGenericProjectType (string projectId, Type type)
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 2a2d5a3148..aec98ee7cc 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
@@ -643,7 +643,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild
DateTime ti = DateTime.Now;
if (sol.IsSolutionItemEnabled (projectPath)) {
- Console.WriteLine (">> Start Loading " + Path.GetFileName (projectPath));
loadTask = Services.ProjectService.ReadSolutionItem (monitor, projectPath, format, projTypeGuid, projectGuid, ctx);
} else {
loadTask = Task.FromResult<SolutionItem> (new UnloadedSolutionItem () {
@@ -653,52 +652,15 @@ namespace MonoDevelop.Projects.Formats.MSBuild
var ft = loadTask.ContinueWith (ta => {
try {
- Console.WriteLine ("<< End Loading " + Path.GetFileName (projectPath) + " t:" + (DateTime.Now - ti).TotalMilliseconds);
item = ta.Result;
if (item == null)
throw new UnknownSolutionItemTypeException (projTypeGuid);
} catch (Exception cex) {
var e = UnwrapException (cex).First ();
- bool loadAsProject = false;
string unsupportedMessage = e.Message;
- if (e is ProjectEvaluationException) {
- var relPath = new FilePath (path).ToRelative (sol.BaseDirectory);
- var project = ((ProjectEvaluationException)e).Project;
- var projectInfo = MSBuildProjectService.GetUnknownProjectTypeInfo (project.ProjectTypeGuids, sol.FileName);
- if (projectInfo != null) {
- loadAsProject = projectInfo.LoadFiles;
- LoggingService.LogWarning (string.Format ("Could not load {0} project '{1}'. {2}", projectInfo.Name, relPath, projectInfo.GetInstructions ()));
- monitor.ReportWarning (GettextCatalog.GetString ("Could not load {0} project '{1}'. {2}", projectInfo.Name, relPath, projectInfo.GetInstructions ()));
- unsupportedMessage = projectInfo.GetInstructions ();
- } else {
- LoggingService.LogWarning (string.Format ("Could not load project '{0}': {1}", relPath, e.Message));
- monitor.ReportWarning (GettextCatalog.GetString ("Could not load project '{0}': {1}'", relPath, e.Message));
- unsupportedMessage = GettextCatalog.GetString ("Project evaluation failed: " + e.Message);
- }
- }
- else if (e is UnknownSolutionItemTypeException) {
- var name = ((UnknownSolutionItemTypeException)e).TypeName;
-
- var relPath = new FilePath (path).ToRelative (sol.BaseDirectory);
- if (!string.IsNullOrEmpty (name)) {
- var guids = name.Split (';');
- 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 ()));
- monitor.ReportWarning (GettextCatalog.GetString ("Could not load {0} project '{1}'. {2}", projectInfo.Name, relPath, projectInfo.GetInstructions ()));
- } else {
- LoggingService.LogWarning (string.Format ("Could not load project '{0}' with unknown item type '{1}'", relPath, name));
- monitor.ReportWarning (GettextCatalog.GetString ("Could not load project '{0}' with unknown item type '{1}'", relPath, name));
- }
- } else {
- LoggingService.LogWarning (string.Format ("Could not load project '{0}' with unknown item type", relPath));
- monitor.ReportWarning (GettextCatalog.GetString ("Could not load project '{0}' with unknown item type", relPath));
- }
-
- } else if (e is UserException) {
+ if (e is UserException) {
var ex = (UserException) e;
LoggingService.LogError ("{0}: {1}", ex.Message, ex.Details);
monitor.ReportError (string.Format ("{0}{1}{1}{2}", ex.Message, Environment.NewLine, ex.Details), null);
@@ -709,17 +671,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild
}
SolutionItem uitem;
- if (loadAsProject) {
- uitem = new UnknownProject () {
- FileName = projectPath,
- UnsupportedProjectMessage = unsupportedMessage,
- };
- } else {
- uitem = new UnknownSolutionItem () {
- FileName = projectPath,
- UnsupportedProjectMessage = unsupportedMessage,
- };
- }
+ uitem = new UnknownSolutionItem () {
+ FileName = projectPath,
+ UnsupportedProjectMessage = unsupportedMessage,
+ };
item = uitem;
item.ItemId = projectGuid;
item.TypeGuid = projTypeGuid;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
index a3b377516c..16584c4677 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
@@ -166,7 +166,8 @@ namespace MonoDevelop.Projects
flavorGuids = subtypeGuids.ToArray ();
}
} else {
- this.sourceProject = null;
+ sourceProject = new MSBuildProject ();
+ sourceProject.FileName = FileName;
flavorGuids = creationContext.FlavorGuids;
}
}
@@ -254,20 +255,22 @@ namespace MonoDevelop.Projects
protected override Task OnLoad (ProgressMonitor monitor)
{
- MSBuildProject p = sourceProject;
-
return Task.Run (delegate {
- if (p == null || p.IsNewProject)
- p = MSBuildProject.LoadAsync (FileName).Result;
+ if (sourceProject == null || sourceProject.IsNewProject) {
+ sourceProject = MSBuildProject.LoadAsync (FileName).Result;
+ if (MSBuildEngineSupport == MSBuildSupport.NotSupported)
+ sourceProject.UseMSBuildEngine = false;
+ sourceProject.Evaluate ();
+ }
- IMSBuildPropertySet globalGroup = p.GetGlobalPropertyGroup ();
+ IMSBuildPropertySet globalGroup = sourceProject.GetGlobalPropertyGroup ();
// Avoid crash if there is not global group
if (globalGroup == null)
- p.AddNewPropertyGroup (false);
+ sourceProject.AddNewPropertyGroup (false);
- ProjectExtension.OnPrepareForEvaluation (p);
+ ProjectExtension.OnPrepareForEvaluation (sourceProject);
- ReadProject (monitor, p);
+ ReadProject (monitor, sourceProject);
});
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
index 9295fcf1c4..5a6d34417b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
@@ -128,7 +128,8 @@ namespace MonoDevelop.Projects
using (Counters.ReadSolutionItem.BeginTiming ("Read project " + file)) {
file = GetTargetFile (file);
SolutionItem loadedItem = await GetExtensionChain ().LoadSolutionItem (monitor, ctx, file, format, typeGuid, itemGuid);
- loadedItem.NeedsReload = false;
+ if (loadedItem != null)
+ loadedItem.NeedsReload = false;
return loadedItem;
}
});
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs
index 5074318786..a798b6260f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs
@@ -75,12 +75,6 @@ namespace MonoDevelop.Projects
return GettextCatalog.GetString ("Unknown entry");
}
- internal protected override Task OnSave (ProgressMonitor monitor)
- {
- // Do nothing
- return Task.FromResult (0);
- }
-
protected override bool OnGetSupportsTarget (string target)
{
// We can't do anything with unsupported projects, other than display them in the solution pad