C#: Save copy of sln and csproj before applying fixes
(cherry picked from commit 93d7ec8836
)
This commit is contained in:
parent
a5bbd13794
commit
08f41f474b
|
@ -0,0 +1,27 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace GodotTools.Core
|
||||||
|
{
|
||||||
|
public static class FileUtils
|
||||||
|
{
|
||||||
|
public static void SaveBackupCopy(string filePath)
|
||||||
|
{
|
||||||
|
string backupPathBase = filePath + ".old";
|
||||||
|
string backupPath = backupPathBase;
|
||||||
|
|
||||||
|
const int maxAttempts = 5;
|
||||||
|
int attempt = 1;
|
||||||
|
|
||||||
|
while (File.Exists(backupPath) && attempt <= maxAttempts)
|
||||||
|
{
|
||||||
|
backupPath = backupPathBase + "." + (attempt);
|
||||||
|
attempt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt > maxAttempts + 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
File.Copy(filePath, backupPath, overwrite: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="FileUtils.cs" />
|
||||||
<Compile Include="ProcessExtensions.cs" />
|
<Compile Include="ProcessExtensions.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="StringExtensions.cs" />
|
<Compile Include="StringExtensions.cs" />
|
||||||
|
|
|
@ -153,7 +153,12 @@ EndProject";
|
||||||
var result = regex.Replace(input,m => dict[m.Value]);
|
var result = regex.Replace(input,m => dict[m.Value]);
|
||||||
|
|
||||||
if (result != input)
|
if (result != input)
|
||||||
|
{
|
||||||
|
// Save a copy of the solution before replacing it
|
||||||
|
FileUtils.SaveBackupCopy(slnPath);
|
||||||
|
|
||||||
File.WriteAllText(slnPath, result);
|
File.WriteAllText(slnPath, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,28 @@ using Microsoft.Build.Construction;
|
||||||
|
|
||||||
namespace GodotTools.ProjectEditor
|
namespace GodotTools.ProjectEditor
|
||||||
{
|
{
|
||||||
|
public sealed class MSBuildProject
|
||||||
|
{
|
||||||
|
public ProjectRootElement Root { get; }
|
||||||
|
|
||||||
|
public bool HasUnsavedChanges => Root.HasUnsavedChanges;
|
||||||
|
|
||||||
|
public void Save() => Root.Save();
|
||||||
|
|
||||||
|
public MSBuildProject(ProjectRootElement root)
|
||||||
|
{
|
||||||
|
Root = root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class ProjectUtils
|
public static class ProjectUtils
|
||||||
{
|
{
|
||||||
|
public static MSBuildProject Open(string path)
|
||||||
|
{
|
||||||
|
var root = ProjectRootElement.Open(path);
|
||||||
|
return root != null ? new MSBuildProject(root) : null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void AddItemToProjectChecked(string projectPath, string itemType, string include)
|
public static void AddItemToProjectChecked(string projectPath, string itemType, string include)
|
||||||
{
|
{
|
||||||
var dir = Directory.GetParent(projectPath).FullName;
|
var dir = Directory.GetParent(projectPath).FullName;
|
||||||
|
@ -43,7 +63,6 @@ namespace GodotTools.ProjectEditor
|
||||||
|
|
||||||
public static void RemoveItemFromProjectChecked(string projectPath, string itemType, string include)
|
public static void RemoveItemFromProjectChecked(string projectPath, string itemType, string include)
|
||||||
{
|
{
|
||||||
var dir = Directory.GetParent(projectPath).FullName;
|
|
||||||
var root = ProjectRootElement.Open(projectPath);
|
var root = ProjectRootElement.Open(projectPath);
|
||||||
Debug.Assert(root != null);
|
Debug.Assert(root != null);
|
||||||
|
|
||||||
|
@ -59,8 +78,6 @@ namespace GodotTools.ProjectEditor
|
||||||
var root = ProjectRootElement.Open(projectPath);
|
var root = ProjectRootElement.Open(projectPath);
|
||||||
Debug.Assert(root != null);
|
Debug.Assert(root != null);
|
||||||
|
|
||||||
bool dirty = false;
|
|
||||||
|
|
||||||
var oldFolderNormalized = oldFolder.NormalizePath();
|
var oldFolderNormalized = oldFolder.NormalizePath();
|
||||||
var newFolderNormalized = newFolder.NormalizePath();
|
var newFolderNormalized = newFolder.NormalizePath();
|
||||||
string absOldFolderNormalized = Path.GetFullPath(oldFolderNormalized).NormalizePath();
|
string absOldFolderNormalized = Path.GetFullPath(oldFolderNormalized).NormalizePath();
|
||||||
|
@ -71,10 +88,9 @@ namespace GodotTools.ProjectEditor
|
||||||
string absPathNormalized = Path.GetFullPath(item.Include).NormalizePath();
|
string absPathNormalized = Path.GetFullPath(item.Include).NormalizePath();
|
||||||
string absNewIncludeNormalized = absNewFolderNormalized + absPathNormalized.Substring(absOldFolderNormalized.Length);
|
string absNewIncludeNormalized = absNewFolderNormalized + absPathNormalized.Substring(absOldFolderNormalized.Length);
|
||||||
item.Include = absNewIncludeNormalized.RelativeToPath(dir).Replace("/", "\\");
|
item.Include = absNewIncludeNormalized.RelativeToPath(dir).Replace("/", "\\");
|
||||||
dirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dirty)
|
if (root.HasUnsavedChanges)
|
||||||
root.Save();
|
root.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,12 +166,9 @@ namespace GodotTools.ProjectEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simple function to make sure the Api assembly references are configured correctly
|
/// Simple function to make sure the Api assembly references are configured correctly
|
||||||
public static void FixApiHintPath(string projectPath)
|
public static void FixApiHintPath(MSBuildProject project)
|
||||||
{
|
{
|
||||||
var root = ProjectRootElement.Open(projectPath);
|
var root = project.Root;
|
||||||
Debug.Assert(root != null);
|
|
||||||
|
|
||||||
bool dirty = false;
|
|
||||||
|
|
||||||
void AddPropertyIfNotPresent(string name, string condition, string value)
|
void AddPropertyIfNotPresent(string name, string condition, string value)
|
||||||
{
|
{
|
||||||
|
@ -170,7 +183,6 @@ namespace GodotTools.ProjectEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
root.AddProperty(name, value).Condition = " " + condition + " ";
|
root.AddProperty(name, value).Condition = " " + condition + " ";
|
||||||
dirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddPropertyIfNotPresent(name: "ApiConfiguration",
|
AddPropertyIfNotPresent(name: "ApiConfiguration",
|
||||||
|
@ -212,7 +224,6 @@ namespace GodotTools.ProjectEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
referenceWithHintPath.AddMetadata("HintPath", hintPath);
|
referenceWithHintPath.AddMetadata("HintPath", hintPath);
|
||||||
dirty = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,14 +232,12 @@ namespace GodotTools.ProjectEditor
|
||||||
{
|
{
|
||||||
// Found a Reference item without a HintPath
|
// Found a Reference item without a HintPath
|
||||||
referenceWithoutHintPath.AddMetadata("HintPath", hintPath);
|
referenceWithoutHintPath.AddMetadata("HintPath", hintPath);
|
||||||
dirty = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Found no Reference item at all. Add it.
|
// Found no Reference item at all. Add it.
|
||||||
root.AddItem("Reference", referenceName).Condition = " " + condition + " ";
|
root.AddItem("Reference", referenceName).Condition = " " + condition + " ";
|
||||||
dirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const string coreProjectName = "GodotSharp";
|
const string coreProjectName = "GodotSharp";
|
||||||
|
@ -242,17 +251,11 @@ namespace GodotTools.ProjectEditor
|
||||||
|
|
||||||
SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath);
|
SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath);
|
||||||
SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath);
|
SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath);
|
||||||
|
|
||||||
if (dirty)
|
|
||||||
root.Save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MigrateFromOldConfigNames(string projectPath)
|
public static void MigrateFromOldConfigNames(MSBuildProject project)
|
||||||
{
|
{
|
||||||
var root = ProjectRootElement.Open(projectPath);
|
var root = project.Root;
|
||||||
Debug.Assert(root != null);
|
|
||||||
|
|
||||||
bool dirty = false;
|
|
||||||
|
|
||||||
bool hasGodotProjectGeneratorVersion = false;
|
bool hasGodotProjectGeneratorVersion = false;
|
||||||
bool foundOldConfiguration = false;
|
bool foundOldConfiguration = false;
|
||||||
|
@ -267,7 +270,6 @@ namespace GodotTools.ProjectEditor
|
||||||
{
|
{
|
||||||
configItem.Value = "Debug";
|
configItem.Value = "Debug";
|
||||||
foundOldConfiguration = true;
|
foundOldConfiguration = true;
|
||||||
dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +277,6 @@ namespace GodotTools.ProjectEditor
|
||||||
{
|
{
|
||||||
root.PropertyGroups.First(g => g.Condition == string.Empty)?
|
root.PropertyGroups.First(g => g.Condition == string.Empty)?
|
||||||
.AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
.AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
||||||
dirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundOldConfiguration)
|
if (!foundOldConfiguration)
|
||||||
|
@ -299,33 +300,21 @@ namespace GodotTools.ProjectEditor
|
||||||
void MigrateConditions(string oldCondition, string newCondition)
|
void MigrateConditions(string oldCondition, string newCondition)
|
||||||
{
|
{
|
||||||
foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition.Trim() == oldCondition))
|
foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition.Trim() == oldCondition))
|
||||||
{
|
|
||||||
propertyGroup.Condition = " " + newCondition + " ";
|
propertyGroup.Condition = " " + newCondition + " ";
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var propertyGroup in root.PropertyGroups)
|
foreach (var propertyGroup in root.PropertyGroups)
|
||||||
{
|
{
|
||||||
foreach (var prop in propertyGroup.Properties.Where(p => p.Condition.Trim() == oldCondition))
|
foreach (var prop in propertyGroup.Properties.Where(p => p.Condition.Trim() == oldCondition))
|
||||||
{
|
|
||||||
prop.Condition = " " + newCondition + " ";
|
prop.Condition = " " + newCondition + " ";
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var itemGroup in root.ItemGroups.Where(g => g.Condition.Trim() == oldCondition))
|
foreach (var itemGroup in root.ItemGroups.Where(g => g.Condition.Trim() == oldCondition))
|
||||||
{
|
|
||||||
itemGroup.Condition = " " + newCondition + " ";
|
itemGroup.Condition = " " + newCondition + " ";
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var itemGroup in root.ItemGroups)
|
foreach (var itemGroup in root.ItemGroups)
|
||||||
{
|
{
|
||||||
foreach (var item in itemGroup.Items.Where(item => item.Condition.Trim() == oldCondition))
|
foreach (var item in itemGroup.Items.Where(item => item.Condition.Trim() == oldCondition))
|
||||||
{
|
|
||||||
item.Condition = " " + newCondition + " ";
|
item.Condition = " " + newCondition + " ";
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,10 +329,6 @@ namespace GodotTools.ProjectEditor
|
||||||
MigrateConfigurationConditions("Release", "ExportRelease");
|
MigrateConfigurationConditions("Release", "ExportRelease");
|
||||||
MigrateConfigurationConditions("Tools", "Debug"); // Must be last
|
MigrateConfigurationConditions("Tools", "Debug"); // Must be last
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (dirty)
|
|
||||||
root.Save();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using GodotTools.Core;
|
||||||
using GodotTools.Export;
|
using GodotTools.Export;
|
||||||
using GodotTools.Utils;
|
using GodotTools.Utils;
|
||||||
using System;
|
using System;
|
||||||
|
@ -450,13 +451,27 @@ namespace GodotTools
|
||||||
{
|
{
|
||||||
// Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease
|
// Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease
|
||||||
DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath);
|
DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath);
|
||||||
// Migrate csproj from old configuration names to: Debug, ExportDebug and ExportRelease
|
|
||||||
ProjectUtils.MigrateFromOldConfigNames(GodotSharpDirs.ProjectCsProjPath);
|
|
||||||
|
|
||||||
// Apply the other fixes after configurations are migrated
|
var msbuildProject = ProjectUtils.Open(GodotSharpDirs.ProjectCsProjPath)
|
||||||
|
?? throw new Exception("Cannot open C# project");
|
||||||
|
|
||||||
|
// NOTE: The order in which changes are made to the project is important
|
||||||
|
|
||||||
|
// Migrate csproj from old configuration names to: Debug, ExportDebug and ExportRelease
|
||||||
|
ProjectUtils.MigrateFromOldConfigNames(msbuildProject);
|
||||||
|
|
||||||
|
// Apply the other fixes only after configurations have been migrated
|
||||||
|
|
||||||
// Make sure the existing project has Api assembly references configured correctly
|
// Make sure the existing project has Api assembly references configured correctly
|
||||||
ProjectUtils.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath);
|
ProjectUtils.FixApiHintPath(msbuildProject);
|
||||||
|
|
||||||
|
if (msbuildProject.HasUnsavedChanges)
|
||||||
|
{
|
||||||
|
// Save a copy of the project before replacing it
|
||||||
|
FileUtils.SaveBackupCopy(GodotSharpDirs.ProjectCsProjPath);
|
||||||
|
|
||||||
|
msbuildProject.Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue