From a29f09c35ae680751aeaed4a3a4dfd8134a192f0 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Mon, 12 Apr 2021 16:06:35 -0400 Subject: [PATCH 01/22] [System.Runtime.Loader] Add hot reload test infrastructure Adding infrastructure for hot reload testing. For each test we define a new library assembly project. The `.csproj` has a `DeltaScript` property that specifies a JSON file that lists the name of an initial source file, and a list of updated versions of that file. The `hotreload-delta-gen` tool runs during the build to read the delta script and create deltas that incorporate the updates. The main testsuite references all the test assemblies, and when a test runs, it calls `ApplyUpdateUtil.ApplyUpdate` to load subsequent deltas and then compares the results before and after an update. Dependencies: - https://github.com/dotnet/hotreload-utils the `hotreload-delta-gen` binary must be installed and on the PATH (TODO: package it as a dotnet tool and publish to a transport nuget package) Needs work: - Mono test runs need to pass the `FEATURE_MONO_METADATA_UPDATE` property to msbuild to the test project. This is because not every mono configuration includes hot reload support. Eventually this should be subsumed by the runtime API to querty hot reload capabilities https://github.com/dotnet/runtime/issues/50111 - All runs need to pass `DOTNET_MODIFIABLE_ASSEMBLIES=debug` to the testsuite. Hot reload only works when: - the assemblies are compiled with the Debug compiler setting, - and, if the runtime is tarted with the above environment variable set. - The GenerateHotReloadDeltas.targets needs some output file work to run `hotreload-delta-gen` less frequently. Right now it runs every time even if everything is up to date. For CI testing we should ideally compile the deltas ahead of time once. To try it out locally: 1. checkout and build `hotreload-utils` and do `dotnet publish --self-contained -r ` to put `hotreload-delta-gen` into that projects' `artifacts/...` forlder. Add the publish folder to your `$PATH` 2. In dotnet/runtime run ``` DOTNET_MODIFIABLE_ASSEMBLIES=debug MONO_ENV_OPTIONS=--interp ./dotnet.sh build src/libraries/System.Runtime.Loader/tests /p:MonoMetadataUpdate=true /t:Test ``` (CoreCLR doesn't need `MONO_ENV_OPTIONS` or `MonoMetadataUpdate`) --- .../tests/ApplyUpdate/Directory.Build.props | 3 + .../tests/ApplyUpdate/Directory.Build.targets | 5 ++ .../MethodBody1.cs | 9 +++ .../MethodBody1_v1.cs | 9 +++ .../MethodBody1_v2.cs | 9 +++ ...tadata.ApplyUpdate.Test.MethodBody1.csproj | 17 ++++ .../deltascript.json | 7 ++ .../tests/ApplyUpdateTest.cs | 39 +++++++++ .../tests/GenerateHotReloadDelta.targets | 81 +++++++++++++++++++ .../System.Runtime.Loader/tests/Helpers.cs | 74 +++++++++++++++++ .../tests/System.Runtime.Loader.Tests.csproj | 5 ++ 11 files changed, 258 insertions(+) create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.targets create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v1.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v2.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/deltascript.json create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.targets create mode 100644 src/libraries/System.Runtime.Loader/tests/Helpers.cs diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props new file mode 100644 index 00000000000000..c13ea1ed0a66b0 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props @@ -0,0 +1,3 @@ + + + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.targets b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.targets new file mode 100644 index 00000000000000..69ce9dbaf1d9e2 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1.cs new file mode 100644 index 00000000000000..a58a038f685d17 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1.cs @@ -0,0 +1,9 @@ + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class MethodBody1 { + public static string StaticMethod1 () { + return "OLD STRING"; + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v1.cs new file mode 100644 index 00000000000000..2c514ed7943473 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v1.cs @@ -0,0 +1,9 @@ + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class MethodBody1 { + public static string StaticMethod1 () { + return "NEW STRING"; + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v2.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v2.cs new file mode 100644 index 00000000000000..47814274c11536 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/MethodBody1_v2.cs @@ -0,0 +1,9 @@ + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class MethodBody1 { + public static string StaticMethod1 () { + return "NEWEST STRING"; + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj new file mode 100644 index 00000000000000..e523ed1e46f605 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj @@ -0,0 +1,17 @@ + + + System.Runtime.Loader.Tests + $(NetCoreAppCurrent) + true + + FEATURE_MONO_APPLY_UPDATE + + + + + + + deltascript.json + 2 + + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/deltascript.json new file mode 100644 index 00000000000000..8e738364bc7475 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/deltascript.json @@ -0,0 +1,7 @@ +{ + "changes": [ + {"document": "MethodBody1.cs", "update": "MethodBody1_v1.cs"}, + {"document": "MethodBody1.cs", "update": "MethodBody1_v2.cs"}, + ] +} + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs new file mode 100644 index 00000000000000..c0938288075877 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Reflection.Metadata +{ + /// + /// The general setup for ApplyUpdate tests is: + /// + /// Each test Foo has a corresponding assembly under + /// System.Reflection.Metadata.ApplyUpate.Test.Foo The Foo.csproj has a delta + /// script that applies one or more updates to Foo.dll The ApplyUpdateTest + /// testusuite runs each test in sequence, loading the corresponding + /// assembly, applying an update to it and observing the results. + [Collection(nameof(NoParallelTests))] + [ConditionalClass(typeof(ApplyUpdateUtil), nameof (ApplyUpdateUtil.IsSupported))] + public class ApplyUpdateTest + { + + [Fact] + void StaticMethodBodyUpdate() + { + var r = ApplyUpdate.Test.MethodBody1.StaticMethod1 (); + Assert.Equal ("OLD STRING", r); + + ApplyUpdateUtil.ApplyUpdate(typeof (ApplyUpdate.Test.MethodBody1).Assembly); + + r = ApplyUpdate.Test.MethodBody1.StaticMethod1 (); + Assert.Equal ("NEW STRING", r); + + ApplyUpdateUtil.ApplyUpdate(typeof (ApplyUpdate.Test.MethodBody1).Assembly); + + r = ApplyUpdate.Test.MethodBody1.StaticMethod1 (); + Assert.Equal ("NEWEST STRING", r); + } + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.targets b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.targets new file mode 100644 index 00000000000000..2b52d2b30171ad --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.targets @@ -0,0 +1,81 @@ + + + + + + + hotreload-delta-gen + -msbuild:$(MSBuildProjectFullPath) + + $(HotreloadDeltaGenArgs) -p:Configuration=$(Configuration) + $(HotreloadDeltaGenArgs) -p:RuntimeIdentifier=$(RuntimeIdentifier) + $(HotreloadDeltaGenArgs) -p:BuiltRuntimeConfiguration=$(BuiltRuntimeConfiguration) + $(HotreloadDeltaGenArgs) -script:$(DeltaScript) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + always + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/Helpers.cs b/src/libraries/System.Runtime.Loader/tests/Helpers.cs new file mode 100644 index 00000000000000..57fc56150f0ecb --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/Helpers.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Reflection.Metadata +{ + + [CollectionDefinition("NoParallelTests", DisableParallelization = true)] + public partial class NoParallelTests { } + + public class ApplyUpdateUtil { + // FIXME: Use runtime API https://github.com/dotnet/runtime/issues/50111 when it is approved/implemented + public static bool IsSupported => IsModifiableAssembliesSet && + (!IsMonoRuntime || IsSupportedMonoConfiguration()) && + IsSupportedTestConfiguration(); + + public static bool IsModifiableAssembliesSet => + String.Equals("debug", Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES"), StringComparison.InvariantCultureIgnoreCase); + + // copied from https://github.com/dotnet/arcade/blob/6cc4c1e9e23d5e65e88a8a57216b3d91e9b3d8db/src/Microsoft.DotNet.XUnitExtensions/src/DiscovererHelpers.cs#L16-L17 + private static readonly Lazy s_isMonoRuntime = new Lazy(() => Type.GetType("Mono.RuntimeStructs") != null); + public static bool IsMonoRuntime => s_isMonoRuntime.Value; + + // Not every build of Mono supports ApplyUpdate + internal static bool IsSupportedMonoConfiguration() + { +#if FEATURE_MONO_APPLY_UPDATE + // crude check for interp mode + return System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported && !System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeCompiled; +#else + return false; +#endif + } + + + // Only Debug assemblies are editable + internal static bool IsSupportedTestConfiguration() + { +#if DEBUG + return true; +#else + return false; +#endif + } + + private static System.Collections.Generic.Dictionary assembly_count = new (); + + public static void ApplyUpdate (System.Reflection.Assembly assm) + { + int count; + if (!assembly_count.TryGetValue(assm, out count)) + count = 1; + else + count++; + assembly_count [assm] = count; + + /* FIXME WASM: Location is empty on wasm. Make up a name based on Name */ + string basename = assm.Location; + if (basename == "") + basename = assm.GetName().Name + ".dll"; + Console.WriteLine ($"Apply Delta Update for {basename}, revision {count}"); + + string dmeta_name = $"{basename}.{count}.dmeta"; + string dil_name = $"{basename}.{count}.dil"; + byte[] dmeta_data = System.IO.File.ReadAllBytes (dmeta_name); + byte[] dil_data = System.IO.File.ReadAllBytes (dil_name); + byte[] dpdb_data = null; // TODO also use the dpdb data + + AssemblyExtensions.ApplyUpdate(assm, dmeta_data, dil_data, dpdb_data); + } + } + +} diff --git a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj index 7182a634c5f837..32de7943c03f65 100644 --- a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj +++ b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj @@ -6,14 +6,18 @@ true false + + FEATURE_MONO_APPLY_UPDATE + + @@ -34,6 +38,7 @@ + From 11c95128a3ca988015de48cefedce7775111f497 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Apr 2021 20:22:24 -0400 Subject: [PATCH 02/22] Make a proper task for computing hotreload-delta-gen output files --- .../tests/ApplyUpdate/Directory.Build.props | 2 + .../ComputeDeltaFileOutputNames.cs | 36 +++++++++++ .../GenerateHotReloadDelta.BuildTasks.csproj | 14 +++++ .../tests/GenerateHotReloadDelta.props | 8 +++ .../tests/GenerateHotReloadDelta.targets | 60 ++++--------------- 5 files changed, 73 insertions(+), 47 deletions(-) create mode 100644 src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/ComputeDeltaFileOutputNames.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/GenerateHotReloadDelta.BuildTasks.csproj create mode 100644 src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.props diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props index c13ea1ed0a66b0..3cfa3c9f898417 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/Directory.Build.props @@ -1,3 +1,5 @@ + + diff --git a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/ComputeDeltaFileOutputNames.cs b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/ComputeDeltaFileOutputNames.cs new file mode 100644 index 00000000000000..5b418992e78692 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/ComputeDeltaFileOutputNames.cs @@ -0,0 +1,36 @@ +using System; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class ComputeDeltaFileOutputNames : Task { + [Required] + public string BaseAssemblyName { get; set; } + [Required] + public int DeltaCount { get; set; } + + [Output] + public ITaskItem[] DeltaOutputs { get; set; } + + public override bool Execute () + { + int count = DeltaCount; + if (count == 0) { + Log.LogError("Did not expect 0 deltas"); + return false; + } + string baseAssemblyName = BaseAssemblyName; + ITaskItem[] result = new TaskItem[3*count]; + for (int i = 0; i < count; ++i) { + int rev = 1+i; + string dmeta = baseAssemblyName + $".{rev}.dmeta"; + string dil = baseAssemblyName + $".{rev}.dil"; + string dpdb = baseAssemblyName + $".{rev}.dpdb"; + result[3*i] = new TaskItem(dmeta); + result[3*i+1] = new TaskItem(dil); + result[3*i+2] = new TaskItem(dpdb); + } + DeltaOutputs = result; + return true; + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/GenerateHotReloadDelta.BuildTasks.csproj b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/GenerateHotReloadDelta.BuildTasks.csproj new file mode 100644 index 00000000000000..44ce3a0f6b0895 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/GenerateHotReloadDelta.BuildTasks.csproj @@ -0,0 +1,14 @@ + + + $(NetCoreAppToolCurrent) + false + + + + + + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.props b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.props new file mode 100644 index 00000000000000..8a542d5035c5a8 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.props @@ -0,0 +1,8 @@ + + + + + + <_generateHotReloadDeltaBuildTasks>$([MSBuild]::NormalizePath('$(ArtifactsBinDir)', 'GenerateHotReloadDelta.BuildTasks', '$(NetCoreAppToolCurrent)-$(Configuration)', , 'GenerateHotReloadDelta.BuildTasks.dll')) + + diff --git a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.targets b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.targets index 2b52d2b30171ad..9faecd11edd6a7 100644 --- a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.targets +++ b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.targets @@ -8,7 +8,7 @@ hotreload-delta-gen -msbuild:$(MSBuildProjectFullPath) + What other properties do I need to pass? Maybe hotreload-delta-gen should just expose an MSBuild task so we can pass everything --> $(HotreloadDeltaGenArgs) -p:Configuration=$(Configuration) $(HotreloadDeltaGenArgs) -p:RuntimeIdentifier=$(RuntimeIdentifier) $(HotreloadDeltaGenArgs) -p:BuiltRuntimeConfiguration=$(BuiltRuntimeConfiguration) @@ -17,47 +17,9 @@ - - - - - - - - - - - - - - - - + + @@ -66,16 +28,20 @@ DeltaOutputs = result; + + DependsOnTargets="ComputeDeltaFileOutputNames" + BeforeTargets="AssignTargetPaths" + Condition="'$(DesignTimeBuild)' != 'true' and '$(BuildingProject)' == 'true'" + > - always + always - + From 690b98b00cd820dcc338881d402228c4dfb0003b Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 14 Apr 2021 21:00:06 -0400 Subject: [PATCH 03/22] Don't need DeltaCount property, compute from json Compute the number of deltas that hotreload-delta-gen will produce by parsing the json script and counting the number of changes. --- ...tadata.ApplyUpdate.Test.MethodBody1.csproj | 1 - .../ComputeDeltaFileOutputNames.cs | 22 +++++++--- .../DeltaScriptParser.cs | 41 +++++++++++++++++++ .../GenerateHotReloadDelta.BuildTasks.csproj | 1 + .../tests/GenerateHotReloadDelta.targets | 5 +-- 5 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/DeltaScriptParser.cs diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj index e523ed1e46f605..8427a52e4705a6 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1/System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.csproj @@ -12,6 +12,5 @@ deltascript.json - 2 diff --git a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/ComputeDeltaFileOutputNames.cs b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/ComputeDeltaFileOutputNames.cs index 5b418992e78692..1762559914dc66 100644 --- a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/ComputeDeltaFileOutputNames.cs +++ b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/ComputeDeltaFileOutputNames.cs @@ -1,25 +1,34 @@ using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -public class ComputeDeltaFileOutputNames : Task { +public class ComputeDeltaFileOutputNames : Microsoft.Build.Utilities.Task { [Required] public string BaseAssemblyName { get; set; } [Required] - public int DeltaCount { get; set; } + public string DeltaScript {get; set; } [Output] public ITaskItem[] DeltaOutputs { get; set; } - public override bool Execute () + public override bool Execute() { - int count = DeltaCount; - if (count == 0) { - Log.LogError("Did not expect 0 deltas"); + if (!System.IO.File.Exists (DeltaScript)) { + Log.LogError("Hot reload delta script {0} does not exist", DeltaScript); return false; } string baseAssemblyName = BaseAssemblyName; + int count; + try { + var json = DeltaScriptParser.Parse (DeltaScript).Result; + count = json.Changes.Length; + } catch (System.Text.Json.JsonException exn) { + Log.LogErrorFromException (exn, showStackTrace: true); + return false; + } ITaskItem[] result = new TaskItem[3*count]; for (int i = 0; i < count; ++i) { int rev = 1+i; @@ -33,4 +42,5 @@ public override bool Execute () DeltaOutputs = result; return true; } + } diff --git a/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/DeltaScriptParser.cs b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/DeltaScriptParser.cs new file mode 100644 index 00000000000000..be95e04d38d9d7 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/GenerateHotReloadDelta.BuildTasks/DeltaScriptParser.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using System.Text.Json; +using System.Text.Json.Serialization; + +public class DeltaScriptParser +{ + public static async Task