2023-08-06 23:45:49 +03:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using System.Xml.Linq;
|
|
|
|
|
|
|
2025-10-09 21:40:05 +03:00
|
|
|
|
namespace PascalABCCompiler.NETGenerator
|
2023-08-06 23:45:49 +03:00
|
|
|
|
{
|
|
|
|
|
|
internal static class AppConfigUtil
|
|
|
|
|
|
{
|
|
|
|
|
|
private static class Namespaces
|
|
|
|
|
|
{
|
|
|
|
|
|
public const string Asm = "urn:schemas-microsoft-com:asm.v1";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static class Elements
|
|
|
|
|
|
{
|
|
|
|
|
|
public static readonly XName Configuration = "configuration";
|
|
|
|
|
|
public static readonly XName Runtime = "runtime";
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly XName AssemblyBinding = XName.Get("assemblyBinding", Namespaces.Asm);
|
|
|
|
|
|
public static readonly XName DependentAssembly = XName.Get("dependentAssembly", Namespaces.Asm);
|
|
|
|
|
|
public static readonly XName AssemblyIdentity = XName.Get("assemblyIdentity", Namespaces.Asm);
|
|
|
|
|
|
public static readonly XName BindingRedirect = XName.Get("bindingRedirect", Namespaces.Asm);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void UpdateAppConfig(
|
|
|
|
|
|
ICollection<AssemblyName> bindingRedirects,
|
|
|
|
|
|
string appConfigPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (bindingRedirects.Count == 0) return;
|
|
|
|
|
|
var config = File.Exists(appConfigPath)
|
|
|
|
|
|
? XDocument.Load(appConfigPath)
|
|
|
|
|
|
: new XDocument(new XElement(Elements.Configuration));
|
|
|
|
|
|
var assemblyBinding = config.GetOrCreateElement(
|
|
|
|
|
|
Elements.Configuration,
|
|
|
|
|
|
Elements.Runtime,
|
|
|
|
|
|
Elements.AssemblyBinding);
|
|
|
|
|
|
|
|
|
|
|
|
var hasChanges = false;
|
|
|
|
|
|
foreach (var redirect in bindingRedirects)
|
|
|
|
|
|
{
|
|
|
|
|
|
hasChanges |= assemblyBinding.CreateOrUpdateDependentAssembly(redirect);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (hasChanges)
|
|
|
|
|
|
{
|
|
|
|
|
|
config.Save(appConfigPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static XElement GetOrCreateElement(this XContainer container, params XName[] names)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (names.Length == 0) throw new ArgumentException("names should not be empty.", nameof(names));
|
|
|
|
|
|
|
|
|
|
|
|
var currentPosition = container;
|
|
|
|
|
|
foreach (var name in names)
|
|
|
|
|
|
{
|
|
|
|
|
|
var existingElement = currentPosition.Element(name);
|
|
|
|
|
|
if (existingElement != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
currentPosition = existingElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var newElement = new XElement(name);
|
|
|
|
|
|
currentPosition.Add(newElement);
|
|
|
|
|
|
currentPosition = newElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (XElement)currentPosition;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static bool CreateOrUpdateDependentAssembly(this XContainer assemblyBinding, AssemblyName assemblyName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var assemblyPublicKeyToken = assemblyName.GetPublicKeyToken();
|
|
|
|
|
|
if (assemblyPublicKeyToken == null) return false;
|
|
|
|
|
|
var publicKeyTokenString = string.Join(
|
|
|
|
|
|
"",
|
|
|
|
|
|
assemblyName.GetPublicKeyToken().Select(b => b.ToString("x2", CultureInfo.InvariantCulture)));
|
|
|
|
|
|
var assemblyCulture = string.IsNullOrEmpty(assemblyName.CultureInfo?.Name)
|
|
|
|
|
|
? "neutral"
|
|
|
|
|
|
: assemblyName.CultureInfo?.Name;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var dependentAssembly in assemblyBinding.Elements(Elements.DependentAssembly))
|
|
|
|
|
|
{
|
|
|
|
|
|
var identity = dependentAssembly.Element(Elements.AssemblyIdentity);
|
|
|
|
|
|
if (identity == null) continue;
|
|
|
|
|
|
var name = identity.Attribute("name")?.Value;
|
|
|
|
|
|
var publicKeyToken = identity.Attribute("publicKeyToken")?.Value;
|
|
|
|
|
|
var culture = identity.Attribute("culture")?.Value;
|
|
|
|
|
|
if (string.IsNullOrEmpty(culture)) culture = "neutral";
|
|
|
|
|
|
|
|
|
|
|
|
if (name == assemblyName.Name
|
2023-12-10 13:07:29 +03:00
|
|
|
|
&& publicKeyToken.Equals(publicKeyTokenString, StringComparison.CurrentCultureIgnoreCase)
|
2023-08-06 23:45:49 +03:00
|
|
|
|
&& assemblyCulture == culture)
|
|
|
|
|
|
{
|
|
|
|
|
|
var bindingRedirect = dependentAssembly.GetOrCreateElement(Elements.BindingRedirect);
|
|
|
|
|
|
{
|
2023-12-10 13:07:29 +03:00
|
|
|
|
return UpdateBindingRedirect(assemblyName, bindingRedirect);
|
2023-08-06 23:45:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var newAssembly = new XElement(
|
|
|
|
|
|
Elements.DependentAssembly,
|
2023-12-10 13:07:29 +03:00
|
|
|
|
CreateIdentityElement(assemblyName, publicKeyTokenString, assemblyCulture),
|
|
|
|
|
|
CreateBindingRedirect(assemblyName));
|
2023-08-06 23:45:49 +03:00
|
|
|
|
assemblyBinding.Add(newAssembly);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
2023-12-10 13:07:29 +03:00
|
|
|
|
|
|
|
|
|
|
}
|
2023-08-06 23:45:49 +03:00
|
|
|
|
|
2023-12-10 13:07:29 +03:00
|
|
|
|
static bool UpdateBindingRedirect(AssemblyName assemblyName, XElement bindingRedirect)
|
|
|
|
|
|
{
|
|
|
|
|
|
var newVersion = assemblyName.Version.ToString(4);
|
|
|
|
|
|
var oldVersionRange = $"0.0.0.0-{newVersion}";
|
|
|
|
|
|
var hasChanges =
|
|
|
|
|
|
bindingRedirect.Attribute("oldVersion")?.Value != oldVersionRange
|
|
|
|
|
|
|| bindingRedirect.Attribute("newVersion")?.Value != newVersion;
|
|
|
|
|
|
if (!hasChanges) return false;
|
|
|
|
|
|
|
|
|
|
|
|
bindingRedirect.SetAttributeValue("oldVersion", oldVersionRange);
|
|
|
|
|
|
bindingRedirect.SetAttributeValue("newVersion", newVersion);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2023-08-06 23:45:49 +03:00
|
|
|
|
|
2023-12-10 13:07:29 +03:00
|
|
|
|
static XElement CreateIdentityElement(AssemblyName assemblyName, string publicKeyTokenString, string assemblyCulture)
|
|
|
|
|
|
{
|
|
|
|
|
|
var element = new XElement(Elements.AssemblyIdentity);
|
|
|
|
|
|
element.SetAttributeValue("name", assemblyName.Name);
|
|
|
|
|
|
element.SetAttributeValue("publicKeyToken", publicKeyTokenString);
|
|
|
|
|
|
element.SetAttributeValue("culture", assemblyCulture);
|
|
|
|
|
|
return element;
|
|
|
|
|
|
}
|
2023-08-06 23:45:49 +03:00
|
|
|
|
|
2023-12-10 13:07:29 +03:00
|
|
|
|
static XElement CreateBindingRedirect(AssemblyName assemblyName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var element = new XElement(Elements.BindingRedirect);
|
|
|
|
|
|
UpdateBindingRedirect(assemblyName, element);
|
|
|
|
|
|
return element;
|
2023-08-06 23:45:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|