diff options
author | Lluis Sanchez <lluis@xamarin.com> | 2014-04-01 15:00:09 +0400 |
---|---|---|
committer | Lluis Sanchez <lluis@xamarin.com> | 2014-04-01 15:00:09 +0400 |
commit | e57b52f673ef75ef7597ce195af6d89dc2761950 (patch) | |
tree | 2d0f0a01ce8b515edcd9f1040e1d9f2980a2e58c /main/src/core/MonoDevelop.Core | |
parent | 2fb79caf515824360412632b9f69d6f4e4820374 (diff) |
[Core] MSBuild improvements
Improved handling of imports in MSBuildProject.
Made MSBuildProjectHandler more extensible.
Diffstat (limited to 'main/src/core/MonoDevelop.Core')
3 files changed, 137 insertions, 72 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildExtension.cs index 6b1abcd4e8..adb9f0a0c4 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildExtension.cs @@ -24,17 +24,25 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using MonoDevelop.Core; namespace MonoDevelop.Projects.Formats.MSBuild { public class MSBuildExtension { - public virtual void LoadProject (SolutionEntityItem item, MSBuildProject project) + 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) { } - public virtual void SaveProject (SolutionEntityItem item, MSBuildProject project) + public virtual object GetService (Type t) { + return null; } } } 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 b5cb33b05b..057e5db5e5 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 @@ -40,7 +40,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild { public class MSBuildProject { - public XmlDocument doc; + XmlDocument doc; string file; Dictionary<XmlElement,MSBuildObject> elemCache = new Dictionary<XmlElement,MSBuildObject> (); Dictionary<string, MSBuildItemGroup> bestGroups; @@ -66,6 +66,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild get { return file; } } + public XmlDocument Document { + get { return doc; } + } + public MSBuildProject () { doc = new XmlDocument (); @@ -170,7 +174,12 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void Evaluate () { - MSBuildEvaluationContext context = new MSBuildEvaluationContext (this); + Evaluate (new MSBuildEvaluationContext ()); + } + + public void Evaluate (MSBuildEvaluationContext context) + { + context.InitEvaluation (this); foreach (var pg in PropertyGroups) pg.Evaluate (context); foreach (var pg in ItemGroups) @@ -192,7 +201,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } - public void AddNewImport (string name, string condition) + public MSBuildImport AddNewImport (string name) { XmlElement elem = doc.CreateElement (null, "Import", MSBuildProject.Schema); elem.SetAttribute ("Project", name); @@ -202,6 +211,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild doc.DocumentElement.InsertAfter (elem, last); else doc.DocumentElement.AppendChild (elem); + return new MSBuildImport (elem); } public void RemoveImport (string name) @@ -214,13 +224,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild Console.WriteLine ("ppnf:"); } - public List<string> Imports { + public IEnumerable<MSBuildImport> Imports { get { - List<string> ims = new List<string> (); - foreach (XmlElement elem in doc.DocumentElement.SelectNodes ("tns:Import", XmlNamespaceManager)) { - ims.Add (elem.GetAttribute ("Project")); - } - return ims; + foreach (XmlElement elem in doc.DocumentElement.SelectNodes ("tns:Import", XmlNamespaceManager)) + yield return new MSBuildImport (elem); } } @@ -438,7 +445,12 @@ namespace MonoDevelop.Projects.Formats.MSBuild 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"); @@ -455,6 +467,18 @@ namespace MonoDevelop.Projects.Formats.MSBuild { } } + + public class MSBuildImport: MSBuildObject + { + public MSBuildImport (XmlElement elem): base (elem) + { + } + + public string Project { + get { return EvaluatedElement.GetAttribute ("Project"); } + set { Element.SetAttribute ("Project", value); } + } + } public class MSBuildProperty: MSBuildObject { @@ -878,15 +902,24 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } - internal class MSBuildEvaluationContext: IExpressionContext + public class MSBuildEvaluationContext: IExpressionContext { Dictionary<string,string> properties = new Dictionary<string, string> (); bool allResolved; MSBuildProject project; - public MSBuildEvaluationContext (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)); } public string GetPropertyValue (string name) 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 0b2b77cd31..4a7080b9ac 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 @@ -152,6 +152,16 @@ namespace MonoDevelop.Projects.Formats.MSBuild 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) { @@ -372,7 +382,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild RemoveDuplicateItems (p, fileName); - Load (monitor, p); + LoadProject (monitor, p); return it; } finally { @@ -597,7 +607,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } - void Load (IProgressMonitor monitor, MSBuildProject msproject) + protected virtual void LoadProject (IProgressMonitor monitor, MSBuildProject msproject) { timer.Trace ("Initialize serialization"); @@ -615,31 +625,8 @@ namespace MonoDevelop.Projects.Formats.MSBuild timer.Trace ("Read project items"); - foreach (MSBuildItem buildItem in msproject.GetAllItems ()) { - ProjectItem it = ReadItem (ser, buildItem); - - if (it == null) continue; + LoadProjectItems (msproject, ser, ProjectItemFlags.None); - 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); - } - timer.Trace ("Read configurations"); TargetFrameworkMoniker targetFx = null; @@ -766,15 +753,41 @@ namespace MonoDevelop.Projects.Formats.MSBuild dotNetProject.TargetFramework = Runtime.SystemAssemblyService.GetTargetFramework (targetFx); } - LoadFromMSBuildProject (msproject); + LoadFromMSBuildProject (monitor, msproject); Item.NeedsReload = false; } - protected virtual void LoadFromMSBuildProject (MSBuildProject msproject) + 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 (EntityItem, msproject); + ext.LoadProject (monitor, EntityItem, msproject); } const string RecursiveDirectoryWildcard = "**"; @@ -889,7 +902,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } - ProjectItem ReadItem (MSBuildSerializer ser, MSBuildItem buildItem) + internal ProjectItem ReadItem (MSBuildSerializer ser, MSBuildItem buildItem) { Project project = Item as Project; DotNetProject dotNetProject = Item as DotNetProject; @@ -988,12 +1001,15 @@ namespace MonoDevelop.Projects.Formats.MSBuild { // If it is an absolute uri, it's not a valid file try { - return !Uri.IsWellFormedUriString (path, UriKind.Absolute); + 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; } + return true; } class ConfigData @@ -1069,7 +1085,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild projectBuilder.Refresh (); } - MSBuildProject SaveProject (IProgressMonitor monitor) + protected virtual MSBuildProject SaveProject (IProgressMonitor monitor) { if (Item is UnknownSolutionItem) return null; @@ -1255,19 +1271,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } - // Remove old items - Dictionary<string,ItemInfo> oldItems = new Dictionary<string, ItemInfo> (); - foreach (MSBuildItem item in msproject.GetAllItems ()) - oldItems [item.Name + "<" + item.Include + "<" + item.Condition] = new ItemInfo () { Item=item }; - - // Add the new items - foreach (object ob in ((SolutionEntityItem)Item).Items.Concat (((SolutionEntityItem)Item).WildcardItems)) - SaveItem (monitor, toolsFormat, ser, msproject, ob, oldItems); - - foreach (ItemInfo itemInfo in oldItems.Values) { - if (!itemInfo.Added) - msproject.RemoveItem (itemInfo.Item); - } + SaveProjectItems (monitor, toolsFormat, ser, msproject); if (dotNetProject != null) { var moniker = dotNetProject.TargetFramework.Id; @@ -1288,7 +1292,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild // Impdate the imports section - List<string> currentImports = msproject.Imports; + List<string> currentImports = msproject.Imports.Select (i => i.Project).ToList (); List<string> imports = new List<string> (currentImports); // If the project is not new, don't add the default project imports, @@ -1296,7 +1300,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild UpdateImports (imports, dotNetProject, newProject); foreach (string imp in imports) { if (!currentImports.Contains (imp)) { - msproject.AddNewImport (imp, null); + msproject.AddNewImport (imp); currentImports.Add (imp); } } @@ -1314,15 +1318,32 @@ namespace MonoDevelop.Projects.Formats.MSBuild } else msproject.RemoveProjectExtensions ("MonoDevelop"); - SaveToMSBuildProject (msproject); + SaveToMSBuildProject (monitor, msproject); return msproject; } - protected void SaveToMSBuildProject (MSBuildProject 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.Include + "<" + 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 (EntityItem, msproject); + ext.SaveProject (monitor, EntityItem, msproject); } void SetIfPresentOrNotDefaultValue (MSBuildPropertySet propGroup, string name, string value, string defaultValue, bool isXml = false) @@ -1395,13 +1416,13 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } - void SaveItem (IProgressMonitor monitor, MSBuildFileFormat fmt, MSBuildSerializer ser, MSBuildProject msproject, object ob, Dictionary<string,ItemInfo> oldItems) + 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); + SaveProjectFile (ser, msproject, (ProjectFile) ob, oldItems, pathPrefix); } else { string itemName; @@ -1416,13 +1437,13 @@ namespace MonoDevelop.Projects.Formats.MSBuild } } - void SaveProjectFile (MSBuildSerializer ser, MSBuildProject msproject, ProjectFile file, Dictionary<string,ItemInfo> 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 = MSBuildProjectService.ToMSBuildPath (Item.ItemDirectory, file.FilePath); + string path = pathPrefix + MSBuildProjectService.ToMSBuildPath (Item.ItemDirectory, file.FilePath); if (path.Length == 0) return; @@ -1434,7 +1455,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild WriteBuildItemMetadata (ser, buildItem, file, oldItems); if (!string.IsNullOrEmpty (file.DependsOn)) - buildItem.SetMetadata ("DependentUpon", MSBuildProjectService.ToMSBuildPath (Path.GetDirectoryName (file.FilePath), file.DependsOn)); + buildItem.SetMetadata ("DependentUpon", pathPrefix + MSBuildProjectService.ToMSBuildPath (Path.GetDirectoryName (file.FilePath), file.DependsOn)); else buildItem.UnsetMetadata ("DependentUpon"); @@ -1457,7 +1478,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild buildItem.UnsetMetadata ("LastGenOutput"); if (!string.IsNullOrEmpty (file.Link)) - buildItem.SetMetadata ("Link", MSBuildProjectService.ToMSBuildPathRelative (Item.ItemDirectory, file.Link)); + buildItem.SetMetadata ("Link", pathPrefix + MSBuildProjectService.ToMSBuildPathRelative (Item.ItemDirectory, file.Link)); else buildItem.UnsetMetadata ("Link"); @@ -1620,7 +1641,10 @@ namespace MonoDevelop.Projects.Formats.MSBuild IEnumerable<MSBuildExtension> GetMSBuildExtensions () { - return AddinManager.GetExtensionObjects<MSBuildExtension> ("/MonoDevelop/ProjectModel/MSBuildExtensions"); + 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) |