Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,31 @@ public static string FormatCommandArguments(string bootstrapFile, string? script
var source = string.IsNullOrWhiteSpace(nugetSource) ? "https://api.nuget.org/v3/index.json" : nugetSource;
var commandArguments = new StringBuilder();
commandArguments.Append($"-s {source} ");
// dotnet-script 2.0 turned the isolated assembly load context on by default, which
// changes which assembly a script gets when it references a package that dotnet-script
// also carries: a script asking for Newtonsoft.Json 9.0.1 used to bind to the 13.0.3
// dotnet-script bundles, and under isolation it gets 9.0.1. That is arguably more
// correct, but it is a silent change to what customer scripts run against, so hold the
// existing behaviour here and treat adopting isolation as its own decision.
//
// Unless the customer asked for isolation themselves. When both flags are passed,
// --disable-isolated-load-context wins, so adding it unconditionally would override
// the one group of customers who made a deliberate choice here.
if (!HasIsolatedLoadContextFlag(scriptCommandArguments))
commandArguments.Append("--disable-isolated-load-context ");
if (!string.IsNullOrWhiteSpace(scriptCommandArguments)) commandArguments.Append($"{scriptCommandArguments} ");
commandArguments.AppendFormat("\"{0}\" -- {1} \"{2}\"", bootstrapFile, scriptArguments, encryptionKey);
return commandArguments.ToString();
}

/// <summary>
/// True when the caller already passed --isolated-load-context. Note that
/// --disable-isolated-load-context does not match: "--isolated-load-context" is not a
/// substring of it, because the character before "isolated" there is a single dash.
/// </summary>
static bool HasIsolatedLoadContextFlag(string? scriptCommandArguments)
=> scriptCommandArguments?.IndexOf("--isolated-load-context", StringComparison.OrdinalIgnoreCase) >= 0;

[return: NotNullIfNotNull("scriptParameters")]
static (string? scriptCommandArguments, string? scriptArguments) RetrieveParameterValues(string? scriptParameters)
{
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"runtimeOptions": {
"tfm": "net8.0",
"rollForward": "LatestMajor",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "8.0.0"
},
"configProperties": {
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ public void FormatCommandArgumentsTest([CanBeNull] string scriptParameters, [Can
formattedCommandArgument.Should().Contain($"{commandArguments}\"{bootstrapFile}\" -- {scriptArguments}");
}

[Test]
public void FormatCommandArguments_DisablesIsolatedLoadContext_ByDefault()
{
var result = DotnetScriptBootstrapper.FormatCommandArguments("Bootstrap.csx", null);
result.Should().Contain("--disable-isolated-load-context ");
}

[TestCase("--isolated-load-context -- \"Parameter 1\"")]
[TestCase("--isolated-load-context -d -- \"Parameter 1\"")]
public void FormatCommandArguments_LeavesIsolationOn_WhenTheCallerAskedForIt(string scriptParameters)
{
// Both flags together resolve to disabled, so we must not add ours on top of theirs.
var result = DotnetScriptBootstrapper.FormatCommandArguments("Bootstrap.csx", scriptParameters);
result.Should().NotContain("--disable-isolated-load-context");
result.Should().Contain("--isolated-load-context ");
}

[Test]
public void FormatCommandArguments_UsesCustomNuGetSource_WhenProvided()
{
Expand Down
11 changes: 11 additions & 0 deletions source/IncludeDotNetScript.targets
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@
<Target Name="GetToolFiles" DependsOnTargets="RunResolvePackageDependencies">
<ItemGroup>
<DotnetScriptFiles Include="$(MSBuildProjectDirectory)/../Calamari.Scripting/DotnetScript/dotnet-script.*.zip"/>
<!--
Overwrites the runtimeconfig.json extracted from the zip. The upstream file requests
Microsoft.NETCore.App 8.0.0 with no rollForward, so the default Minor policy binds to
an 8.x runtime and nothing else: dotnet-script fails to launch (exit 150) on a target
that only has a newer runtime, and stays on .NET 8 on a target that has both.
Ours adds "rollForward": "LatestMajor". Keep it in sync with the zip when the
bundled dotnet-script version changes - the rest of the file is upstream's.
-->
<DotnetScriptRuntimeConfig Include="$(MSBuildProjectDirectory)/../Calamari.Scripting/DotnetScript/dotnet-script.runtimeconfig.json"/>
</ItemGroup>
</Target>
<Target Name="CopyDotnetScriptFilesAfterBuild" AfterTargets="Build" DependsOnTargets="GetToolFiles">
<ItemGroup>
<DotnetScriptFilesExe Include="$(OutputPath)/dotnet-script/*.sh;$(OutputPath)/dotnet-script/*.exe"/>
</ItemGroup>
<Unzip SourceFiles="@(DotnetScriptFiles)" DestinationFolder="$(OutputPath)/" />
<Copy SourceFiles="@(DotnetScriptRuntimeConfig)" DestinationFolder="$(OutputPath)/dotnet-script/" />
<Exec Command="chmod +x %(DotnetScriptFilesExe.Identity)" IgnoreExitCode="true" Condition="!$([MSBuild]::IsOSPlatform('Windows'))"/>
</Target>

Expand All @@ -18,6 +28,7 @@
<DotnetScriptFilesExe Include="$(PublishDir)/dotnet-script/*.sh;$(PublishDir)/dotnet-script/*.exe"/>
</ItemGroup>
<Unzip SourceFiles="@(DotnetScriptFiles)" DestinationFolder="$(PublishDir)/" />
<Copy SourceFiles="@(DotnetScriptRuntimeConfig)" DestinationFolder="$(PublishDir)/dotnet-script/" />
<Exec Command="chmod +x %(DotnetScriptFilesExe.Identity)" IgnoreExitCode="true" Condition="!$([MSBuild]::IsOSPlatform('Windows'))"/>
</Target>
</Project>