diff --git a/BuildTools/pre-commit b/BuildTools/pre-commit index 3ba7ae835..b9d352bf6 100644 --- a/BuildTools/pre-commit +++ b/BuildTools/pre-commit @@ -1,26 +1,45 @@ #!/bin/sh # # To enable this hook, copy/symlink this file to ".git/hooks/pre-commit". -# mklink .git\hooks\pre-commit ..\..\BuildTools\pre-commit +# Windows: mklink .git\hooks\pre-commit ..\..\BuildTools\pre-commit +# Linux/Mac: ln -s ../../BuildTools/pre-commit .git/hooks/pre-commit set -eu DOTNET_FORMAT_VERSION=10.0.100-rtm.25531.102 DOTNET_FORMAT_SOURCE="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet10-transport/nuget/v3/index.json" -DOTNET_PATH="$LOCALAPPDATA/ICSharpCode/ILSpy/dotnet-format-$DOTNET_FORMAT_VERSION" + +# Per-OS tool cache location + binary suffix. Windows uses %LOCALAPPDATA% and a .exe +# suffix; Unix-likes follow the XDG basedir spec (falling back to ~/.local/share) and +# drop the suffix. Keeping the tool installed under the same logical path on both +# platforms means a single repo clone can host hook installs from either OS. +case "$(uname -s 2>/dev/null)" in + MINGW*|MSYS*|CYGWIN*|Windows*) + DOTNET_CACHE_ROOT="$LOCALAPPDATA" + EXE_SUFFIX=".exe" + ;; + *) + DOTNET_CACHE_ROOT="${XDG_DATA_HOME:-$HOME/.local/share}" + EXE_SUFFIX="" + ;; +esac + +DOTNET_PATH="$DOTNET_CACHE_ROOT/ICSharpCode/ILSpy/dotnet-format-$DOTNET_FORMAT_VERSION" if [ ! -d "$DOTNET_PATH" ]; then echo "Downloading dotnet-format $DOTNET_FORMAT_VERSION..." dotnet tool install --tool-path "$DOTNET_PATH" dotnet-format --version "$DOTNET_FORMAT_VERSION" --add-source "$DOTNET_FORMAT_SOURCE" fi -"$DOTNET_PATH/dotnet-format.exe" --version +DOTNET_FORMAT="$DOTNET_PATH/dotnet-format$EXE_SUFFIX" + +"$DOTNET_FORMAT" --version if [ "${1:-}" = "--format" ]; then # called via format.bat - "$DOTNET_PATH/dotnet-format.exe" whitespace --no-restore --verbosity detailed ILSpy.sln + "$DOTNET_FORMAT" whitespace --no-restore --verbosity detailed ILSpy.sln elif git diff --quiet --ignore-submodules; then - "$DOTNET_PATH/dotnet-format.exe" whitespace --no-restore --verbosity detailed ILSpy.sln + "$DOTNET_FORMAT" whitespace --no-restore --verbosity detailed ILSpy.sln git add -u -- \*\*.cs else echo Partial commit: only verifying formatting - exec "$DOTNET_PATH/dotnet-format.exe" whitespace --verify-no-changes --no-restore --verbosity detailed ILSpy.sln + exec "$DOTNET_FORMAT" whitespace --verify-no-changes --no-restore --verbosity detailed ILSpy.sln fi diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs index ddcea3a1b..6d8fcea5c 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs @@ -109,6 +109,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers static readonly VsWhereToolset vswhereToolset; internal static readonly RefAssembliesToolset RefAssembliesToolset; + // ilasm/ildasm ship as `ilasm[.exe]` inside the Microsoft.NETCore.IL{,D}Asm + // per-RID runtime packages, picked up by NuGet's RID graph from the project's + // RuntimeIdentifier. The umbrella package drops the binary alongside the test + // assembly, but only Windows uses the .exe suffix. + static readonly string ExecutableExtension = OperatingSystem.IsWindows() ? ".exe" : ""; + + static string ResolveToolPath(string toolName) => + Path.Combine(TesterPath, toolName + ExecutableExtension); + static Tester() { TesterPath = Path.GetDirectoryName(typeof(Tester).Assembly.Location); @@ -145,18 +154,23 @@ namespace ICSharpCode.Decompiler.Tests.Helpers await RefAssembliesToolset.Fetch("9.0.0", sourcePath: "ref/net9.0").ConfigureAwait(false); await RefAssembliesToolset.Fetch(CurrentNetCoreRefAsmVersion, sourcePath: $"ref/net{CurrentNetCoreVersion}").ConfigureAwait(false); + // The self-contained TestRunner builds only target Windows RIDs; the fixtures that + // consume them (UseTestRunner) are themselves gated to Windows at runtime. + if (OperatingSystem.IsWindows()) + { #if DEBUG - await BuildTestRunner("win-x86", "Debug").ConfigureAwait(false); - await BuildTestRunner("win-x64", "Debug").ConfigureAwait(false); + await BuildTestRunner("win-x86", "Debug").ConfigureAwait(false); + await BuildTestRunner("win-x64", "Debug").ConfigureAwait(false); #else - await BuildTestRunner("win-x86", "Release").ConfigureAwait(false); - await BuildTestRunner("win-x64", "Release").ConfigureAwait(false); + await BuildTestRunner("win-x86", "Release").ConfigureAwait(false); + await BuildTestRunner("win-x64", "Release").ConfigureAwait(false); #endif + } } static async Task BuildTestRunner(string runtime, string config) { - await Cli.Wrap("dotnet.exe") + await Cli.Wrap("dotnet") .WithArguments(new[] { "build", Path.Combine(TesterPath, "../../../../../ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj"), "-r", runtime, "-c", config, "--self-contained" }) .ExecuteAsync(); } @@ -166,13 +180,13 @@ namespace ICSharpCode.Decompiler.Tests.Helpers string ilasmPath; if (options.HasFlag(AssemblerOptions.UseLegacyAssembler)) { + if (!OperatingSystem.IsWindows()) + Assert.Ignore("UseLegacyAssembler requires the .NET Framework ilasm.exe, which only exists on Windows."); ilasmPath = Path.Combine(Environment.GetEnvironmentVariable("windir"), @"Microsoft.NET\Framework\v4.0.30319\ilasm.exe"); } else { - ilasmPath = Path.Combine( - Path.GetDirectoryName(typeof(Tester).Assembly.Location), - "ilasm.exe"); + ilasmPath = ResolveToolPath("ilasm"); } string outputFile = Path.Combine(Path.GetDirectoryName(sourceFileName), Path.GetFileNameWithoutExtension(sourceFileName)); string otherOptions = " "; @@ -246,9 +260,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers return outputFile; } - string ildasmPath = Path.Combine( - Path.GetDirectoryName(typeof(Tester).Assembly.Location), - "ildasm.exe"); + string ildasmPath = ResolveToolPath("ildasm"); var command = Cli.Wrap(ildasmPath) .WithArguments($"/utf8 /out=\"{outputFile}\" \"{sourceFileName}\"") @@ -869,6 +881,8 @@ namespace System.Runtime.CompilerServices public static async Task<(int ExitCode, string Output, string Error)> RunWithTestRunner(string assemblyFileName, bool force32Bit) { + if (!OperatingSystem.IsWindows()) + Assert.Ignore("RunWithTestRunner uses a self-contained Windows test-runner build (win-x86/win-x64); not available on this platform."); string testRunner = Path.Combine(testRunnerBasePath, force32Bit ? "win-x86" : "win-x64", "ICSharpCode.Decompiler.TestRunner.exe"); var command = Cli.Wrap(testRunner) .WithArguments(assemblyFileName) @@ -1023,6 +1037,8 @@ namespace System.Runtime.CompilerServices public static async Task SignAssembly(string assemblyPath, string keyFilePath) { + if (!OperatingSystem.IsWindows()) + Assert.Ignore("SignAssembly uses sn.exe from the Windows .NET Framework SDK; not available on this platform."); string snPath = SdkUtility.GetSdkPath("sn.exe"); var command = Cli.Wrap(snPath) @@ -1044,6 +1060,8 @@ namespace System.Runtime.CompilerServices public static async Task FindMSBuild() { + if (!OperatingSystem.IsWindows()) + Assert.Ignore("FindMSBuild uses vswhere.exe to locate Visual Studio's MSBuild; not available on this platform."); string path = vswhereToolset.GetVsWhere(); var result = await Cli.Wrap(path) diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index 8d1d26f7d..0aad546f0 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -2,15 +2,9 @@ - true - true - - - - net11.0-windows + net11.0 preview - win-x64 - win-arm64 + $([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier) false @@ -21,7 +15,11 @@ True - $(NoWarn);1701;1702;1705,67,169,1058,728,1720,649,168,251,660,661,675;1998;162;8632;626;8618;8714;8602;8981;NU1902;NU1903 + + $(NoWarn);1701;1702;1705,67,169,1058,728,1720,649,168,251,660,661,675;1998;162;8632;626;8618;8714;8602;8981;NU1902;NU1903;CA1416 ROSLYN;ROSLYN2;ROSLYN3;ROSLYN4;NET60;CS60;CS70;CS71;CS72;CS73;CS80;CS90;CS100;CS110;CS120;CS130 False @@ -65,7 +63,7 @@ - + diff --git a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs index 8f79d5b27..dc1808f10 100644 --- a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs +++ b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs @@ -36,7 +36,7 @@ using NUnit.Framework; namespace ICSharpCode.Decompiler.Roundtrip { - [TestFixture, Parallelizable(ParallelScope.All)] + [TestFixture, Parallelizable(ParallelScope.All), Platform("Win")] public class RoundtripAssembly { public static readonly string TestDir = Path.GetFullPath(Path.Combine(Tester.TestCasePath, "../../ILSpy-tests")); diff --git a/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs b/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs index ce1091f37..a7077bcd3 100644 --- a/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs @@ -34,7 +34,7 @@ using NUnit.Framework; namespace ICSharpCode.ILSpy.Tests.Analyzers { - [TestFixture, Parallelizable(ParallelScope.All)] + [TestFixture] public class MemberImplementsInterfaceAnalyzerTests { static readonly SymbolKind[] ValidSymbolKinds = { SymbolKind.Event, SymbolKind.Indexer, SymbolKind.Method, SymbolKind.Property }; diff --git a/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs b/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs index ed88104b7..c58cf41a9 100644 --- a/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs @@ -14,7 +14,7 @@ using NUnit.Framework; namespace ICSharpCode.ILSpy.Tests.Analyzers { - [TestFixture, Parallelizable(ParallelScope.All)] + [TestFixture] public class MethodUsesAnalyzerTests { AssemblyList assemblyList; diff --git a/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs b/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs index 4e8835d63..637165e8d 100644 --- a/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs @@ -27,7 +27,7 @@ using NUnit.Framework; namespace ICSharpCode.ILSpy.Tests.Analyzers { - [TestFixture, Parallelizable(ParallelScope.All)] + [TestFixture] public class TypeUsedByAnalyzerTests { AssemblyList assemblyList;