| 
									
										
										
										
											2019-07-03 09:44:53 +02:00
										 |  |  | using GodotTools.Core; | 
					
						
							| 
									
										
										
										
											2018-10-22 19:43:19 +02:00
										 |  |  | using System.Collections.Generic; | 
					
						
							| 
									
										
										
										
											2019-07-10 21:53:49 +02:00
										 |  |  | using System.Diagnostics; | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | using System.IO; | 
					
						
							| 
									
										
										
										
											2019-07-10 21:53:49 +02:00
										 |  |  | using System.Linq; | 
					
						
							| 
									
										
										
										
											2018-10-22 19:43:19 +02:00
										 |  |  | using DotNet.Globbing; | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | using Microsoft.Build.Construction; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-03 09:44:53 +02:00
										 |  |  | namespace GodotTools.ProjectEditor | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     public static class ProjectUtils | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         public static void AddItemToProjectChecked(string projectPath, string itemType, string include) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             var dir = Directory.GetParent(projectPath).FullName; | 
					
						
							|  |  |  |             var root = ProjectRootElement.Open(projectPath); | 
					
						
							| 
									
										
										
										
											2019-07-10 21:53:49 +02:00
										 |  |  |             Debug.Assert(root != null); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 19:43:19 +02:00
										 |  |  |             var normalizedInclude = include.RelativeToPath(dir).Replace("/", "\\"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (root.AddItemChecked(itemType, normalizedInclude)) | 
					
						
							| 
									
										
										
										
											2017-10-05 00:10:51 +02:00
										 |  |  |                 root.Save(); | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-22 19:43:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         private static string[] GetAllFilesRecursive(string rootDirectory, string mask) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             string[] files = Directory.GetFiles(rootDirectory, mask, SearchOption.AllDirectories); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // We want relative paths | 
					
						
							| 
									
										
										
										
											2019-07-10 21:53:49 +02:00
										 |  |  |             for (int i = 0; i < files.Length; i++) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-10-22 19:43:19 +02:00
										 |  |  |                 files[i] = files[i].RelativeToPath(rootDirectory); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return files; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public static string[] GetIncludeFiles(string projectPath, string itemType) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             var result = new List<string>(); | 
					
						
							|  |  |  |             var existingFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 21:53:49 +02:00
										 |  |  |             var globOptions = new GlobOptions(); | 
					
						
							| 
									
										
										
										
											2018-10-22 19:43:19 +02:00
										 |  |  |             globOptions.Evaluation.CaseInsensitive = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var root = ProjectRootElement.Open(projectPath); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             foreach (var itemGroup in root.ItemGroups) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (itemGroup.Condition.Length != 0) | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 foreach (var item in itemGroup.Items) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     if (item.ItemType != itemType) | 
					
						
							|  |  |  |                         continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     string normalizedInclude = item.Include.NormalizePath(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     var glob = Glob.Parse(normalizedInclude, globOptions); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-03 09:44:53 +02:00
										 |  |  |                     // TODO Check somehow if path has no blob to avoid the following loop... | 
					
						
							| 
									
										
										
										
											2018-10-22 19:43:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     foreach (var existingFile in existingFiles) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         if (glob.IsMatch(existingFile)) | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             result.Add(existingFile); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return result.ToArray(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-07-10 21:53:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ///  Simple function to make sure the Api assembly references are configured correctly | 
					
						
							|  |  |  |         public static void FixApiHintPath(string projectPath) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             var root = ProjectRootElement.Open(projectPath); | 
					
						
							|  |  |  |             Debug.Assert(root != null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             bool dirty = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             void AddPropertyIfNotPresent(string name, string condition, string value) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (root.PropertyGroups | 
					
						
							| 
									
										
										
										
											2019-07-25 21:06:40 +02:00
										 |  |  |                     .Any(g => (g.Condition == string.Empty || g.Condition == condition) && | 
					
						
							| 
									
										
										
										
											2019-07-10 21:53:49 +02:00
										 |  |  |                               g.Properties | 
					
						
							|  |  |  |                                   .Any(p => p.Name == name && | 
					
						
							|  |  |  |                                             p.Value == value && | 
					
						
							|  |  |  |                                             (p.Condition == condition || g.Condition == condition)))) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 root.AddProperty(name, value).Condition = condition; | 
					
						
							|  |  |  |                 dirty = true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             AddPropertyIfNotPresent(name: "ApiConfiguration", | 
					
						
							|  |  |  |                 condition: " '$(Configuration)' != 'Release' ", | 
					
						
							|  |  |  |                 value: "Debug"); | 
					
						
							|  |  |  |             AddPropertyIfNotPresent(name: "ApiConfiguration", | 
					
						
							|  |  |  |                 condition: " '$(Configuration)' == 'Release' ", | 
					
						
							|  |  |  |                 value: "Release"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             void SetReferenceHintPath(string referenceName, string condition, string hintPath) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 foreach (var itemGroup in root.ItemGroups.Where(g => | 
					
						
							|  |  |  |                     g.Condition == string.Empty || g.Condition == condition)) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     var references = itemGroup.Items.Where(item => | 
					
						
							|  |  |  |                         item.ItemType == "Reference" && | 
					
						
							|  |  |  |                         item.Include == referenceName && | 
					
						
							|  |  |  |                         (item.Condition == condition || itemGroup.Condition == condition)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     var referencesWithHintPath = references.Where(reference => | 
					
						
							|  |  |  |                         reference.Metadata.Any(m => m.Name == "HintPath")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (referencesWithHintPath.Any(reference => reference.Metadata | 
					
						
							|  |  |  |                         .Any(m => m.Name == "HintPath" && m.Value == hintPath))) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         // Found a Reference item with the right HintPath | 
					
						
							|  |  |  |                         return; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     var referenceWithHintPath = referencesWithHintPath.FirstOrDefault(); | 
					
						
							|  |  |  |                     if (referenceWithHintPath != null) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         // Found a Reference item with a wrong HintPath | 
					
						
							|  |  |  |                         foreach (var metadata in referenceWithHintPath.Metadata.ToList() | 
					
						
							|  |  |  |                             .Where(m => m.Name == "HintPath")) | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             // Safe to remove as we duplicate with ToList() to loop | 
					
						
							|  |  |  |                             referenceWithHintPath.RemoveChild(metadata); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         referenceWithHintPath.AddMetadata("HintPath", hintPath); | 
					
						
							|  |  |  |                         dirty = true; | 
					
						
							|  |  |  |                         return; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     var referenceWithoutHintPath = references.FirstOrDefault(); | 
					
						
							|  |  |  |                     if (referenceWithoutHintPath != null) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         // Found a Reference item without a HintPath | 
					
						
							|  |  |  |                         referenceWithoutHintPath.AddMetadata("HintPath", hintPath); | 
					
						
							|  |  |  |                         dirty = true; | 
					
						
							|  |  |  |                         return; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // Found no Reference item at all. Add it. | 
					
						
							|  |  |  |                 root.AddItem("Reference", referenceName).Condition = condition; | 
					
						
							|  |  |  |                 dirty = true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const string coreProjectName = "GodotSharp"; | 
					
						
							|  |  |  |             const string editorProjectName = "GodotSharpEditor"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const string coreCondition = ""; | 
					
						
							|  |  |  |             const string editorCondition = " '$(Configuration)' == 'Tools' "; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var coreHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{coreProjectName}.dll"; | 
					
						
							|  |  |  |             var editorHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{editorProjectName}.dll"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath); | 
					
						
							|  |  |  |             SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (dirty) | 
					
						
							|  |  |  |                 root.Save(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-10-02 23:24:00 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } |