diff options
Diffstat (limited to 'modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs')
-rw-r--r-- | modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs | 341 |
1 files changed, 27 insertions, 314 deletions
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs index 8774b4ee31..4041c56597 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs @@ -1,9 +1,9 @@ +using System; using GodotTools.Core; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using Microsoft.Build.Construction; using Microsoft.Build.Globbing; @@ -11,7 +11,7 @@ namespace GodotTools.ProjectEditor { public sealed class MSBuildProject { - public ProjectRootElement Root { get; } + internal ProjectRootElement Root { get; set; } public bool HasUnsavedChanges { get; set; } @@ -31,91 +31,7 @@ namespace GodotTools.ProjectEditor return root != null ? new MSBuildProject(root) : null; } - public static void AddItemToProjectChecked(string projectPath, string itemType, string include) - { - var dir = Directory.GetParent(projectPath).FullName; - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - var normalizedInclude = include.RelativeToPath(dir).Replace("/", "\\"); - - if (root.AddItemChecked(itemType, normalizedInclude)) - root.Save(); - } - - public static void RenameItemInProjectChecked(string projectPath, string itemType, string oldInclude, string newInclude) - { - var dir = Directory.GetParent(projectPath).FullName; - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - var normalizedOldInclude = oldInclude.NormalizePath(); - var normalizedNewInclude = newInclude.NormalizePath(); - - var item = root.FindItemOrNullAbs(itemType, normalizedOldInclude); - - if (item == null) - return; - - item.Include = normalizedNewInclude.RelativeToPath(dir).Replace("/", "\\"); - root.Save(); - } - - public static void RemoveItemFromProjectChecked(string projectPath, string itemType, string include) - { - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - var normalizedInclude = include.NormalizePath(); - - if (root.RemoveItemChecked(itemType, normalizedInclude)) - root.Save(); - } - - public static void RenameItemsToNewFolderInProjectChecked(string projectPath, string itemType, string oldFolder, string newFolder) - { - var dir = Directory.GetParent(projectPath).FullName; - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - bool dirty = false; - - var oldFolderNormalized = oldFolder.NormalizePath(); - var newFolderNormalized = newFolder.NormalizePath(); - string absOldFolderNormalized = Path.GetFullPath(oldFolderNormalized).NormalizePath(); - string absNewFolderNormalized = Path.GetFullPath(newFolderNormalized).NormalizePath(); - - foreach (var item in root.FindAllItemsInFolder(itemType, oldFolderNormalized)) - { - string absPathNormalized = Path.GetFullPath(item.Include).NormalizePath(); - string absNewIncludeNormalized = absNewFolderNormalized + absPathNormalized.Substring(absOldFolderNormalized.Length); - item.Include = absNewIncludeNormalized.RelativeToPath(dir).Replace("/", "\\"); - dirty = true; - } - - if (dirty) - root.Save(); - } - - public static void RemoveItemsInFolderFromProjectChecked(string projectPath, string itemType, string folder) - { - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - var folderNormalized = folder.NormalizePath(); - - var itemsToRemove = root.FindAllItemsInFolder(itemType, folderNormalized).ToList(); - - if (itemsToRemove.Count > 0) - { - foreach (var item in itemsToRemove) - item.Parent.RemoveChild(item); - - root.Save(); - } - } - - private static string[] GetAllFilesRecursive(string rootDirectory, string mask) + private static List<string> GetAllFilesRecursive(string rootDirectory, string mask) { string[] files = Directory.GetFiles(rootDirectory, mask, SearchOption.AllDirectories); @@ -125,262 +41,59 @@ namespace GodotTools.ProjectEditor files[i] = files[i].RelativeToPath(rootDirectory); } - return files; + return new List<string>(files); } - public static string[] GetIncludeFiles(string projectPath, string itemType) + // NOTE: Assumes auto-including items. Only used by the scripts metadata generator, which will be replaced with source generators in the future. + public static IEnumerable<string> GetIncludeFiles(string projectPath, string itemType) { - var result = new List<string>(); - var existingFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs"); + var excluded = new List<string>(); + var includedFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs"); var root = ProjectRootElement.Open(projectPath); Debug.Assert(root != null); - foreach (var itemGroup in root.ItemGroups) + foreach (var item in root.Items) { - if (itemGroup.Condition.Length != 0) + if (string.IsNullOrEmpty(item.Condition)) continue; - foreach (var item in itemGroup.Items) - { - if (item.ItemType != itemType) - continue; - - string normalizedInclude = item.Include.NormalizePath(); + if (item.ItemType != itemType) + continue; - var glob = MSBuildGlob.Parse(normalizedInclude); + string normalizedExclude = item.Exclude.NormalizePath(); - // TODO Check somehow if path has no blob to avoid the following loop... + var glob = MSBuildGlob.Parse(normalizedExclude); - foreach (var existingFile in existingFiles) - { - if (glob.IsMatch(existingFile)) - { - result.Add(existingFile); - } - } - } + excluded.AddRange(includedFiles.Where(includedFile => glob.IsMatch(includedFile))); } - return result.ToArray(); + includedFiles.RemoveAll(f => excluded.Contains(f)); + + return includedFiles; } - public static void EnsureHasProjectTypeGuids(MSBuildProject project) + public static void MigrateToProjectSdksStyle(MSBuildProject project, string projectName) { - var root = project.Root; - - bool found = root.PropertyGroups.Any(pg => - string.IsNullOrEmpty(pg.Condition) && pg.Properties.Any(p => p.Name == "ProjectTypeGuids")); + var origRoot = project.Root; - if (found) + if (!string.IsNullOrEmpty(origRoot.Sdk)) return; - root.AddProperty("ProjectTypeGuids", ProjectGenerator.GodotDefaultProjectTypeGuids); - + project.Root = ProjectGenerator.GenGameProject(projectName); + project.Root.FullPath = origRoot.FullPath; project.HasUnsavedChanges = true; } - /// Simple function to make sure the Api assembly references are configured correctly - public static void FixApiHintPath(MSBuildProject project) - { - var root = project.Root; - - void AddPropertyIfNotPresent(string name, string condition, string value) - { - if (root.PropertyGroups - .Any(g => (string.IsNullOrEmpty(g.Condition) || g.Condition.Trim() == condition) && - g.Properties - .Any(p => p.Name == name && - p.Value == value && - (p.Condition.Trim() == condition || g.Condition.Trim() == condition)))) - { - return; - } - - root.AddProperty(name, value).Condition = " " + condition + " "; - project.HasUnsavedChanges = true; - } - - AddPropertyIfNotPresent(name: "ApiConfiguration", - condition: "'$(Configuration)' != 'ExportRelease'", - value: "Debug"); - AddPropertyIfNotPresent(name: "ApiConfiguration", - condition: "'$(Configuration)' == 'ExportRelease'", - value: "Release"); - - void SetReferenceHintPath(string referenceName, string condition, string hintPath) - { - foreach (var itemGroup in root.ItemGroups.Where(g => - g.Condition.Trim() == string.Empty || g.Condition.Trim() == condition)) - { - var references = itemGroup.Items.Where(item => - item.ItemType == "Reference" && - item.Include == referenceName && - (item.Condition.Trim() == condition || itemGroup.Condition.Trim() == 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); - project.HasUnsavedChanges = true; - return; - } - - var referenceWithoutHintPath = references.FirstOrDefault(); - if (referenceWithoutHintPath != null) - { - // Found a Reference item without a HintPath - referenceWithoutHintPath.AddMetadata("HintPath", hintPath); - project.HasUnsavedChanges = true; - return; - } - } - - // Found no Reference item at all. Add it. - root.AddItem("Reference", referenceName).Condition = " " + condition + " "; - project.HasUnsavedChanges = true; - } - - const string coreProjectName = "GodotSharp"; - const string editorProjectName = "GodotSharpEditor"; - - const string coreCondition = ""; - const string editorCondition = "'$(Configuration)' == 'Debug'"; - - var coreHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{coreProjectName}.dll"; - var editorHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{editorProjectName}.dll"; - - SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath); - SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath); - } - - public static void MigrateFromOldConfigNames(MSBuildProject project) - { - var root = project.Root; - - bool hasGodotProjectGeneratorVersion = false; - bool foundOldConfiguration = false; - - foreach (var propertyGroup in root.PropertyGroups.Where(g => string.IsNullOrEmpty(g.Condition))) - { - if (!hasGodotProjectGeneratorVersion && propertyGroup.Properties.Any(p => p.Name == "GodotProjectGeneratorVersion")) - hasGodotProjectGeneratorVersion = true; - - foreach (var configItem in propertyGroup.Properties - .Where(p => p.Condition.Trim() == "'$(Configuration)' == ''" && p.Value == "Tools")) - { - configItem.Value = "Debug"; - foundOldConfiguration = true; - project.HasUnsavedChanges = true; - } - } - - if (!hasGodotProjectGeneratorVersion) - { - root.PropertyGroups.First(g => string.IsNullOrEmpty(g.Condition))? - .AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString()); - project.HasUnsavedChanges = true; - } - - if (!foundOldConfiguration) - { - var toolsConditions = new[] - { - "'$(Configuration)|$(Platform)' == 'Tools|AnyCPU'", - "'$(Configuration)|$(Platform)' != 'Tools|AnyCPU'", - "'$(Configuration)' == 'Tools'", - "'$(Configuration)' != 'Tools'" - }; - - foundOldConfiguration = root.PropertyGroups - .Any(g => toolsConditions.Any(c => c == g.Condition.Trim())); - } - - if (foundOldConfiguration) - { - void MigrateConfigurationConditions(string oldConfiguration, string newConfiguration) - { - void MigrateConditions(string oldCondition, string newCondition) - { - foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition.Trim() == oldCondition)) - { - propertyGroup.Condition = " " + newCondition + " "; - project.HasUnsavedChanges = true; - } - - foreach (var propertyGroup in root.PropertyGroups) - { - foreach (var prop in propertyGroup.Properties.Where(p => p.Condition.Trim() == oldCondition)) - { - prop.Condition = " " + newCondition + " "; - project.HasUnsavedChanges = true; - } - } - - foreach (var itemGroup in root.ItemGroups.Where(g => g.Condition.Trim() == oldCondition)) - { - itemGroup.Condition = " " + newCondition + " "; - project.HasUnsavedChanges = true; - } - - foreach (var itemGroup in root.ItemGroups) - { - foreach (var item in itemGroup.Items.Where(item => item.Condition.Trim() == oldCondition)) - { - item.Condition = " " + newCondition + " "; - project.HasUnsavedChanges = true; - } - } - } - - foreach (var op in new[] {"==", "!="}) - { - MigrateConditions($"'$(Configuration)|$(Platform)' {op} '{oldConfiguration}|AnyCPU'", $"'$(Configuration)|$(Platform)' {op} '{newConfiguration}|AnyCPU'"); - MigrateConditions($"'$(Configuration)' {op} '{oldConfiguration}'", $"'$(Configuration)' {op} '{newConfiguration}'"); - } - } - - MigrateConfigurationConditions("Debug", "ExportDebug"); - MigrateConfigurationConditions("Release", "ExportRelease"); - MigrateConfigurationConditions("Tools", "Debug"); // Must be last - } - } - - public static void EnsureHasNugetNetFrameworkRefAssemblies(MSBuildProject project) + public static void EnsureGodotSdkIsUpToDate(MSBuildProject project) { var root = project.Root; + string godotSdkAttrValue = ProjectGenerator.GodotSdkAttrValue; - bool found = root.ItemGroups.Any(g => string.IsNullOrEmpty(g.Condition) && g.Items.Any( - item => item.ItemType == "PackageReference" && item.Include == "Microsoft.NETFramework.ReferenceAssemblies")); - - if (found) + if (!string.IsNullOrEmpty(root.Sdk) && root.Sdk.Trim().Equals(godotSdkAttrValue, StringComparison.OrdinalIgnoreCase)) return; - var frameworkRefAssembliesItem = root.AddItem("PackageReference", "Microsoft.NETFramework.ReferenceAssemblies"); - - // Use metadata (child nodes) instead of attributes for the PackageReference. - // This is for compatibility with 3.2, where GodotTools uses an old Microsoft.Build. - frameworkRefAssembliesItem.AddMetadata("Version", "1.0.0"); - frameworkRefAssembliesItem.AddMetadata("PrivateAssets", "All"); - + root.Sdk = godotSdkAttrValue; project.HasUnsavedChanges = true; } } |