Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VCST-1438: Fix 32/64 bit conflict when copying DLL files #2811

Merged
merged 17 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions VirtoCommerce.Platform.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=auditable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hangfire/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=postgre/@EntryIndexedValue">True</s:Boolean>
Expand Down
16 changes: 16 additions & 0 deletions src/VirtoCommerce.Platform.Core/Modularity/FileCompareResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace VirtoCommerce.Platform.Core.Modularity;

public class FileCompareResult
{
public bool NewFile { get; set; }
public bool NewDate { get; set; }

public bool SameVersion { get; set; }
public bool NewVersion { get; set; }
public bool SameOrNewVersion => SameVersion || NewVersion;

public bool CompatibleArchitecture { get; set; }
public bool SameArchitecture { get; set; }
public bool NewArchitecture { get; set; }
public bool SameOrNewArchitecture => SameArchitecture || NewArchitecture;
}
8 changes: 8 additions & 0 deletions src/VirtoCommerce.Platform.Core/Modularity/IFileCopyPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Runtime.InteropServices;

namespace VirtoCommerce.Platform.Core.Modularity;

public interface IFileCopyPolicy
{
bool IsCopyRequired(Architecture environment, string sourceFilePath, string targetFilePath, out FileCompareResult result);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Runtime.InteropServices;

namespace VirtoCommerce.Platform.Core.Modularity
{
public interface IFileMetadataProvider
{
bool Exists(string filePath);
DateTime? GetDate(string filePath);
Version GetVersion(string filePath);
Architecture? GetArchitecture(string filePath);
}
}
64 changes: 64 additions & 0 deletions src/VirtoCommerce.Platform.Modules/Local/FileCopyPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Runtime.InteropServices;
using VirtoCommerce.Platform.Core.Modularity;

namespace VirtoCommerce.Platform.Modules.Local;

public class FileCopyPolicy : IFileCopyPolicy
{
private readonly IFileMetadataProvider _metadataProvider;

public FileCopyPolicy(IFileMetadataProvider metadataProvider)
{
_metadataProvider = metadataProvider;
}

public bool IsCopyRequired(Architecture environment, string sourceFilePath, string targetFilePath, out FileCompareResult result)
{
result = new FileCompareResult
{
NewFile = !_metadataProvider.Exists(targetFilePath),
};

CompareDates(sourceFilePath, targetFilePath, result);
CompareVersions(sourceFilePath, targetFilePath, result);
CompareArchitecture(sourceFilePath, targetFilePath, environment, result);

return result.NewFile && result.CompatibleArchitecture ||
result.NewVersion && result.SameOrNewArchitecture ||
result.NewArchitecture && result.SameOrNewVersion ||
result.NewDate && result.SameOrNewArchitecture && result.SameOrNewVersion;
}

private void CompareDates(string sourceFilePath, string targetFilePath, FileCompareResult result)
{
var sourceDate = _metadataProvider.GetDate(sourceFilePath);
var targetDate = _metadataProvider.GetDate(targetFilePath);

result.NewDate = sourceDate > targetDate;
}

private void CompareVersions(string sourceFilePath, string targetFilePath, FileCompareResult result)
{
var sourceVersion = _metadataProvider.GetVersion(sourceFilePath);
var targetVersion = _metadataProvider.GetVersion(targetFilePath);

result.SameVersion = sourceVersion == targetVersion;
result.NewVersion = targetVersion is not null && sourceVersion > targetVersion;
}

private void CompareArchitecture(string sourceFilePath, string targetFilePath, Architecture environment, FileCompareResult result)
{
var sourceArchitecture = _metadataProvider.GetArchitecture(sourceFilePath);
var targetArchitecture = _metadataProvider.GetArchitecture(targetFilePath);

result.CompatibleArchitecture = sourceArchitecture == targetArchitecture ||
sourceArchitecture == environment ||
sourceArchitecture == Architecture.X86 && environment == Architecture.X64;

if (result.CompatibleArchitecture)
{
result.SameArchitecture = sourceArchitecture == targetArchitecture;
result.NewArchitecture = sourceArchitecture == environment && targetArchitecture != environment;
}
}
}
100 changes: 100 additions & 0 deletions src/VirtoCommerce.Platform.Modules/Local/FileMetadataProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Options;
using VirtoCommerce.Platform.Core.Modularity;

namespace VirtoCommerce.Platform.Modules.Local;

public class FileMetadataProvider : IFileMetadataProvider
{
private readonly LocalStorageModuleCatalogOptions _options;

public FileMetadataProvider(IOptions<LocalStorageModuleCatalogOptions> options)
{
_options = options.Value;
}

public bool Exists(string filePath)
{
return File.Exists(filePath);
}

public DateTime? GetDate(string filePath)
{
if (!File.Exists(filePath))
{
return null;
}

var fileInfo = new FileInfo(filePath);

return fileInfo.LastWriteTimeUtc;
}

public Version GetVersion(string filePath)
{
if (!File.Exists(filePath))
{
return null;
}

var fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath);

return new Version(
fileVersionInfo.FileMajorPart,
fileVersionInfo.FileMinorPart,
fileVersionInfo.FileBuildPart,
fileVersionInfo.FilePrivatePart);
}

public Architecture? GetArchitecture(string filePath)
{
if (!_options.AssemblyFileExtensions.Any(x => filePath.EndsWith(x, StringComparison.OrdinalIgnoreCase)))
{
return null;
}

const int startPosition = 0x3C;
const int peSignature = 0x00004550;

var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists || fileInfo.Length < startPosition + sizeof(uint))
{
return null;
}

using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using var reader = new BinaryReader(stream);

stream.Seek(startPosition, SeekOrigin.Begin);
var peOffset = reader.ReadUInt32();

if (fileInfo.Length < peOffset + sizeof(uint) + sizeof(ushort))
{
return null;
}

stream.Seek(peOffset, SeekOrigin.Begin);
var peHead = reader.ReadUInt32();

if (peHead != peSignature)
{
return null;
}

var machineType = reader.ReadUInt16();

// https://stackoverflow.com/questions/480696/how-to-find-if-a-native-dll-file-is-compiled-as-x64-or-x86
return machineType switch
{
0x8664 => Architecture.X64,
0xAA64 => Architecture.Arm64,
0x1C0 => Architecture.Arm,
0x14C => Architecture.X86,
_ => null
};
}
}
Loading
Loading