149 lines
6.8 KiB
C#
149 lines
6.8 KiB
C#
#nullable enable
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Linq;
|
|
|
|
namespace ShrinkSDK.Godot.Editor;
|
|
|
|
public static class ShrinkProjectPackageEditor
|
|
{
|
|
public static readonly IReadOnlyDictionary<string, string> RecommendedPackages =
|
|
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
["ShrinkSDK.Godot"] = "0.1.0",
|
|
["ShrinkSDK.EventBus"] = "2.1.0",
|
|
["ShrinkSDK.Context.Core"] = "0.2.0",
|
|
["ShrinkSDK.Command"] = "0.3.0",
|
|
["ShrinkSDK.Command.Integration.EventBus"] = "0.2.0",
|
|
["ShrinkSDK.Command.Integration.Network"] = "0.2.0",
|
|
["ShrinkSDK.Command.Integration.App"] = "0.2.0",
|
|
["ShrinkSDK.Network"] = "0.3.0",
|
|
["ShrinkSDK.Network.Integration.EventBus"] = "0.2.0",
|
|
["ShrinkSDK.Network.Integration.App"] = "0.2.0",
|
|
["ShrinkSDK.DataSaver"] = "2.3.0",
|
|
["ShrinkSDK.DataSaver.Integration.EventBus"] = "2.2.0",
|
|
["ShrinkSDK.DataSaver.Integration.App"] = "0.2.0",
|
|
["ShrinkSDK.App.Core"] = "0.2.0",
|
|
["ShrinkSDK.Context.AppAdapter"] = "0.2.0",
|
|
["ShrinkSDK.App.Starter.Basic"] = "0.3.0",
|
|
["ShrinkSDK.ModFramework"] = "0.3.0",
|
|
["ShrinkSDK.ModFramework.Godot"] = "0.1.0",
|
|
["ShrinkSDK.Tutorial"] = "0.2.0",
|
|
["ShrinkSDK.Tutorial.Godot"] = "0.1.0"
|
|
};
|
|
|
|
public static IReadOnlyDictionary<string, string> ReadPackageReferences(string projectPath)
|
|
{
|
|
var document = XDocument.Load(projectPath, LoadOptions.PreserveWhitespace);
|
|
return document.Descendants("PackageReference")
|
|
.Select(element => new
|
|
{
|
|
Id = ((string?)element.Attribute("Include") ?? (string?)element.Attribute("Update"))?.Trim(),
|
|
Version = ((string?)element.Attribute("Version") ??
|
|
(string?)element.Attribute("VersionOverride") ??
|
|
element.Element("Version")?.Value)?.Trim() ?? string.Empty
|
|
})
|
|
.Where(item => !string.IsNullOrWhiteSpace(item.Id))
|
|
.GroupBy(item => item.Id!, StringComparer.OrdinalIgnoreCase)
|
|
.ToDictionary(group => group.Key, group => group.First().Version, StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
public static void SetPackageReference(string projectPath, string packageId, string? version)
|
|
{
|
|
var document = XDocument.Load(projectPath, LoadOptions.PreserveWhitespace);
|
|
var root = document.Root ?? throw new InvalidDataException("The C# project has no root element.");
|
|
var references = root.Descendants("PackageReference").Where(element =>
|
|
string.Equals((string?)element.Attribute("Include"), packageId, StringComparison.OrdinalIgnoreCase)).ToArray();
|
|
foreach (var duplicate in references.Skip(1)) duplicate.Remove();
|
|
if (string.IsNullOrWhiteSpace(version))
|
|
{
|
|
foreach (var reference in references) reference.Remove();
|
|
}
|
|
else if (references.Length > 0)
|
|
{
|
|
var reference = references[0];
|
|
if (reference.Attribute("VersionOverride") != null)
|
|
reference.SetAttributeValue("VersionOverride", version);
|
|
else if (reference.Attribute("Version") != null)
|
|
reference.SetAttributeValue("Version", version);
|
|
else if (reference.Element("Version") != null)
|
|
reference.Element("Version")!.Value = version;
|
|
else
|
|
reference.SetAttributeValue("Version", version);
|
|
}
|
|
else
|
|
{
|
|
var group = root.Elements("ItemGroup").FirstOrDefault(element => element.Elements("PackageReference").Any());
|
|
if (group == null)
|
|
{
|
|
group = new XElement("ItemGroup");
|
|
root.Add(group);
|
|
}
|
|
group.Add(new XElement("PackageReference", new XAttribute("Include", packageId), new XAttribute("Version", version)));
|
|
}
|
|
WriteAtomically(projectPath, document);
|
|
}
|
|
|
|
public static void EnsureShrinkFeed(string nugetConfigPath)
|
|
{
|
|
XDocument document;
|
|
if (File.Exists(nugetConfigPath)) document = XDocument.Load(nugetConfigPath, LoadOptions.PreserveWhitespace);
|
|
else document = new XDocument(new XDeclaration("1.0", "utf-8", null), new XElement("configuration"));
|
|
var root = document.Root ?? throw new InvalidDataException("NuGet.Config has no root element.");
|
|
var sources = root.Element("packageSources");
|
|
if (sources == null)
|
|
{
|
|
sources = new XElement("packageSources");
|
|
root.Add(sources);
|
|
}
|
|
var existing = sources.Elements("add").FirstOrDefault(element =>
|
|
string.Equals((string?)element.Attribute("key"), "ShrinkSDK", StringComparison.OrdinalIgnoreCase));
|
|
if (existing == null)
|
|
sources.Add(new XElement("add", new XAttribute("key", "ShrinkSDK"),
|
|
new XAttribute("value", "https://git.crash.work/api/packages/ShrinkSDK/nuget/index.json")));
|
|
else
|
|
existing.SetAttributeValue("value", "https://git.crash.work/api/packages/ShrinkSDK/nuget/index.json");
|
|
WriteAtomically(nugetConfigPath, document);
|
|
}
|
|
|
|
public static async Task<(int ExitCode, string Output)> RunDotnetAsync(string projectDirectory,
|
|
string arguments, CancellationToken cancellationToken = default)
|
|
{
|
|
var output = new StringBuilder();
|
|
using var process = new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo("dotnet", arguments)
|
|
{
|
|
WorkingDirectory = projectDirectory,
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
CreateNoWindow = true
|
|
}
|
|
};
|
|
process.OutputDataReceived += (_, args) => { if (args.Data != null) output.AppendLine(args.Data); };
|
|
process.ErrorDataReceived += (_, args) => { if (args.Data != null) output.AppendLine(args.Data); };
|
|
process.Start();
|
|
process.BeginOutputReadLine();
|
|
process.BeginErrorReadLine();
|
|
await process.WaitForExitAsync(cancellationToken);
|
|
return (process.ExitCode, output.ToString());
|
|
}
|
|
|
|
private static void WriteAtomically(string path, XDocument document)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))!);
|
|
var temporaryPath = path + ".shrinksdk.tmp";
|
|
using (var writer = new StreamWriter(temporaryPath, false, new UTF8Encoding(false)))
|
|
document.Save(writer, SaveOptions.DisableFormatting);
|
|
File.Move(temporaryPath, path, true);
|
|
}
|
|
}
|