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 @@ -5,10 +5,16 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<StrongNameKeyId>MicrosoftAspNetCore</StrongNameKeyId>
<SignAssembly>true</SignAssembly>
<PublicSign Condition=" '$([MSBuild]::IsOSPlatform(`Windows`))' == 'false' ">true</PublicSign>
<PublicSign Condition="'$([MSBuild]::IsOSPlatform(`Windows`))' == 'false'">true</PublicSign>
<RepositoryType>git</RepositoryType>
<DefineConstants Condition="'$(IncludeAspNetCoreRuntime)' == 'false'">$(DefineConstants);EXCLUDE_ASPNETCORE</DefineConstants>
<IsPackable>true</IsPackable>

<!--
Mark as Native AOT compatible. This will enable relevant analyzers.
https://learn.microsoft.com/dotnet/core/deploying/native-aot/#aot-compatibility-analyzers
-->
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<StrongNameKeyId>MicrosoftAspNetCore</StrongNameKeyId>
<SignAssembly>true</SignAssembly>
<PublicSign Condition=" '$([MSBuild]::IsOSPlatform(`Windows`))' == 'false' ">true</PublicSign>
<PublicSign Condition="'$([MSBuild]::IsOSPlatform(`Windows`))' == 'false'">true</PublicSign>
<RepositoryType>git</RepositoryType>
<IsPackable>true</IsPackable>

<!--
Mark as Native AOT compatible. This will enable relevant analyzers.
https://learn.microsoft.com/dotnet/core/deploying/native-aot/#aot-compatibility-analyzers
-->
<IsAotCompatible Condition="'$(TargetFramework)' != 'net472'">true</IsAotCompatible>
</PropertyGroup>

<ItemGroup>
Expand Down
21 changes: 13 additions & 8 deletions src/Cli/Microsoft.TemplateEngine.Cli/CliTemplateEngineHost.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
using Microsoft.TemplateEngine.Abstractions;
Expand All @@ -25,14 +27,17 @@ public CliTemplateEngineHost(
builtIns,
fallbackHostNames,
loggerFactory: Microsoft.Extensions.Logging.LoggerFactory.Create(builder =>
builder
.SetMinimumLevel(logLevel)
.AddConsole(config => config.FormatterName = nameof(CliConsoleFormatter))
.AddConsoleFormatter<CliConsoleFormatter, ConsoleFormatterOptions>(config =>
{
config.IncludeScopes = true;
config.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff";
})))
{
builder
.SetMinimumLevel(logLevel)
.AddConsole(config => config.FormatterName = nameof(CliConsoleFormatter));
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ConsoleFormatter, CliConsoleFormatter>());
builder.Services.Configure<ConsoleFormatterOptions>(config =>
{
config.IncludeScopes = true;
config.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff";
});
}))
{
string workingPath = FileSystem.GetCurrentDirectory();
IsCustomOutputPath = outputPath != null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
<DefineConstants>$(DefineConstants);WCWIDTH_VISIBILITY_INTERNAL</DefineConstants>
<StrongNameKeyId>MicrosoftAspNetCore</StrongNameKeyId>
<SignAssembly>true</SignAssembly>

<!--
Mark as Native AOT compatible. This will enable relevant analyzers.
https://learn.microsoft.com/dotnet/core/deploying/native-aot/#aot-compatibility-analyzers
-->
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/dotnet/BuildServer/VBCSCompilerServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal class VBCSCompilerServer(ICommandFactory commandFactory = null) : IBuil
private static readonly string s_shutdownArg = "-shutdown";

internal static readonly string VBCSCompilerPath = Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
AppContext.BaseDirectory,
"Roslyn",
"bincore",
"VBCSCompiler.dll");
Expand Down
19 changes: 10 additions & 9 deletions src/Cli/dotnet/CliSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Text.Json;
using System.Text.Json.Schema;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Microsoft.DotNet.Cli.Telemetry;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Cli.Utils.Extensions;
Expand All @@ -21,17 +20,16 @@ internal static class CliSchema
// Using UnsafeRelaxedJsonEscaping because this JSON is not transmitted over the web. Therefore, HTML-sensitive characters are not encoded.
// See: https://learn.microsoft.com/dotnet/api/system.text.encodings.web.javascriptencoder.unsaferelaxedjsonescaping
// Force the newline to be "\n" instead of the default "\r\n" for consistency across platforms (and for testing)
private static readonly JsonSerializerOptions s_jsonSerializerOptions = new()
// Using a source-generated JsonSerializerContext as the TypeInfoResolver so that
// the options are AOT compatible and have a resolver set (avoiding https://github.com/dotnet/aspnetcore/issues/55692).
private static readonly CliSchemaJsonSerializerContext s_jsonContext = new(new JsonSerializerOptions
{
WriteIndented = true,
NewLine = "\n",
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
RespectNullableAnnotations = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
// needed to workaround https://github.com/dotnet/aspnetcore/issues/55692, but will need to be removed when
// we tackle AOT in favor of the source-generated JsonTypeInfo stuff
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
};
});

public record ArgumentDetails(string? description, int order, bool hidden, string? helpName, string valueType, bool hasDefaultValue, object? defaultValue, ArityDetails arity);
public record ArityDetails(int minimum, int? maximum);
Expand Down Expand Up @@ -70,7 +68,7 @@ public static void PrintCliSchema(CommandResult commandResult, TextWriter output
{
var command = commandResult.Command;
RootCommandDetails transportStructure = CreateRootCommandDetails(command);
var result = JsonSerializer.Serialize(transportStructure, s_jsonSerializerOptions);
var result = JsonSerializer.Serialize(transportStructure, s_jsonContext.RootCommandDetails);
outputWriter.Write(result.AsSpan());
outputWriter.Flush();
var commandString = CommandHierarchyAsString(commandResult);
Expand All @@ -80,8 +78,8 @@ public static void PrintCliSchema(CommandResult commandResult, TextWriter output

public static object GetJsonSchema()
{
var node = s_jsonSerializerOptions.GetJsonSchemaAsNode(typeof(RootCommandDetails), new JsonSchemaExporterOptions());
return node.ToJsonString(s_jsonSerializerOptions);
var node = s_jsonContext.Options.GetJsonSchemaAsNode(typeof(RootCommandDetails), new JsonSchemaExporterOptions());
return node.ToJsonString(s_jsonContext.Options);
}

private static ArityDetails CreateArityDetails(ArgumentArity arity)
Expand Down Expand Up @@ -222,3 +220,6 @@ private static string CommandHierarchyAsString(CommandResult commandResult)
return string.Join(" ", commands.AsEnumerable().Reverse());
}
}

[JsonSerializable(typeof(CliSchema.RootCommandDetails))]
internal partial class CliSchemaJsonSerializerContext : JsonSerializerContext;
2 changes: 2 additions & 0 deletions src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ private static MSBuildArgs ConcatTelemetryLogger(MSBuildArgs msbuildArgs)
Type loggerType = typeof(MSBuildLogger);
Type forwardingLoggerType = typeof(MSBuildForwardingLogger);

#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
msbuildArgs.OtherMSBuildArgs.Add($"-distributedlogger:{loggerType.FullName},{loggerType.GetTypeInfo().Assembly.Location}*{forwardingLoggerType.FullName},{forwardingLoggerType.GetTypeInfo().Assembly.Location}");
#pragma warning restore IL3000
return msbuildArgs;
}
catch (Exception)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ private static IEnumerable<string> GetTemplateFolders(IEngineEnvironmentSettings
{
var templateFoldersToInstall = new List<string>();

#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
var sdkDirectory = Path.GetDirectoryName(typeof(Utils.DotnetFiles).Assembly.Location);
#pragma warning restore IL3000

var dotnetRootPath = Path.GetDirectoryName(Path.GetDirectoryName(sdkDirectory));

// First grab templates from dotnet\templates\M.m folders, in ascending order, up to our version
Expand Down
2 changes: 2 additions & 0 deletions src/Cli/dotnet/Commands/New/OptionalWorkloadProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ public Task<IReadOnlyList<ITemplatePackage>> GetAllTemplatePackagesAsync(Cancell
{
var list = new List<TemplatePackage>();
var optionalWorkloadLocator = new TemplateLocator.TemplateLocator();
#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
var sdkDirectory = Path.GetDirectoryName(typeof(DotnetFiles).Assembly.Location);
#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
var sdkVersion = Path.GetFileName(sdkDirectory);
var dotnetRootPath = Path.GetDirectoryName(Path.GetDirectoryName(sdkDirectory));
string userProfileDir = CliFolderPathCalculator.DotnetUserProfileFolderPath;
Expand Down
36 changes: 22 additions & 14 deletions src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CommandLine;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -21,6 +22,11 @@ namespace Microsoft.DotNet.Cli.Commands.Run;
/// </summary>
internal sealed partial class CSharpCompilerCommand
{
[JsonSerializable(typeof(string))]
private partial class CSharpCompilerCommandJsonSerializerContext : JsonSerializerContext
{
}

private static readonly SearchValues<char> s_additionalShouldSurroundWithQuotes = SearchValues.Create('=', ',');

/// <summary>
Expand Down Expand Up @@ -277,6 +283,8 @@ private void PrepareAuxiliaryFiles(out string rspPath)
""");
}

// NOTE: MSBuild writes empty values as "property = " (with a trailing space).
// Use an interpolation expression to preserve the trailing space from editor trimming.
string editorconfig = Path.Join(objDir, $"{fileNameWithoutExtension}.GeneratedMSBuildEditorConfig.editorconfig");
if (ShouldEmit(editorconfig))
{
Expand All @@ -285,25 +293,25 @@ private void PrepareAuxiliaryFiles(out string rspPath)
build_property.EnableAotAnalyzer = true
build_property.EnableSingleFileAnalyzer = true
build_property.EnableTrimAnalyzer = true
build_property.IncludeAllContentForSelfExtract =
build_property.VerifyReferenceTrimCompatibility =
build_property.VerifyReferenceAotCompatibility =
build_property.IncludeAllContentForSelfExtract ={" "}
build_property.VerifyReferenceTrimCompatibility ={" "}
build_property.VerifyReferenceAotCompatibility ={" "}
build_property.TargetFramework = net{TargetFrameworkVersion}
build_property.TargetFrameworkIdentifier = .NETCoreApp
build_property.TargetFrameworkVersion = v{TargetFrameworkVersion}
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property.TargetPlatformMinVersion ={" "}
build_property.UsingMicrosoftNETSdkWeb ={" "}
build_property.ProjectTypeGuids ={" "}
build_property.InvariantGlobalization ={" "}
build_property.PlatformNeutralAssembly ={" "}
build_property.EnforceExtendedAnalyzerRules ={" "}
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = {fileNameWithoutExtension}
build_property.ProjectDir = {fileDirectory}{Path.DirectorySeparatorChar}
build_property.EnableComHosting =
build_property.EnableComHosting ={" "}
build_property.EnableGeneratedComInterfaceComImportInterop = false
build_property.EffectiveAnalysisLevelStyle = {TargetFrameworkVersion}
build_property.EnableCodeStyleSeverity =
build_property.EnableCodeStyleSeverity ={" "}

""");
}
Expand All @@ -329,11 +337,11 @@ private void PrepareAuxiliaryFiles(out string rspPath)
"tfm": "net{{TargetFrameworkVersion}}",
"framework": {
"name": "Microsoft.NETCore.App",
"version": {{JsonSerializer.Serialize(DefaultRuntimeVersion)}}
"version": {{JsonSerializer.Serialize(DefaultRuntimeVersion, CSharpCompilerCommandJsonSerializerContext.Default.String)}}
},
"configProperties": {
"EntryPointFilePath": {{JsonSerializer.Serialize(EntryPointFileFullPath)}},
"EntryPointFileDirectoryPath": {{JsonSerializer.Serialize(fileDirectory)}},
"EntryPointFilePath": {{JsonSerializer.Serialize(EntryPointFileFullPath, CSharpCompilerCommandJsonSerializerContext.Default.String)}},
"EntryPointFileDirectoryPath": {{JsonSerializer.Serialize(fileDirectory, CSharpCompilerCommandJsonSerializerContext.Default.String)}},
"Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability": true,
"System.ComponentModel.DefaultValueAttribute.IsSupported": false,
"System.ComponentModel.Design.IDesignerHost.IsSupported": false,
Expand Down
6 changes: 5 additions & 1 deletion src/Cli/dotnet/Commands/Sdk/Check/SdkCheckCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System.CommandLine;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.NativeWrapper;
using EnvironmentProvider = Microsoft.DotNet.NativeWrapper.EnvironmentProvider;
Expand All @@ -29,7 +30,7 @@ public SdkCheckCommand(
{
_dotnetPath = dotnetRoot ?? EnvironmentProvider.GetDotnetExeDirectory();
var configFilePath = Path.Combine(_dotnetPath, "sdk", dotnetVersion ?? Product.Version, "sdk-check-config.json");
_sdkCheckConfig = File.Exists(configFilePath) ? JsonSerializer.Deserialize<SdkCheckConfig>(File.ReadAllText(configFilePath)) : null;
_sdkCheckConfig = File.Exists(configFilePath) ? JsonSerializer.Deserialize(File.ReadAllText(configFilePath), SdkCheckJsonSerializerContext.Default.SdkCheckConfig) : null;
_reporter = reporter ?? Reporter.Output;
_netBundleProvider = bundleProvider == null ? new NETBundlesNativeWrapper() : bundleProvider;
_productCollectionProvider = productCollectionProvider == null ? new ProductCollectionProvider() : productCollectionProvider;
Expand Down Expand Up @@ -89,3 +90,6 @@ internal class SdkCheckConfig
public string ReleasesFilePath { get; set; }
public string CommandOutputReplacementString { get; set; }
}

[JsonSerializable(typeof(SdkCheckConfig))]
internal partial class SdkCheckJsonSerializerContext : JsonSerializerContext;
13 changes: 5 additions & 8 deletions src/Cli/dotnet/Commands/Test/TestCommandDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,7 @@ public static TestCommandDefinition Create()

string jsonText = File.ReadAllText(globalJsonPath);

// This code path is hit exactly once during the whole life of the dotnet process.
// So, no concern about caching JsonSerializerOptions.
var globalJson = JsonSerializer.Deserialize<GlobalJsonModel>(jsonText, new JsonSerializerOptions()
{
AllowDuplicateProperties = false,
AllowTrailingCommas = false,
ReadCommentHandling = JsonCommentHandling.Skip,
});
var globalJson = JsonSerializer.Deserialize(jsonText, GlobalJsonSerializerContext.Default.GlobalJsonModel);

var name = globalJson?.Test?.RunnerName;

Expand Down Expand Up @@ -90,4 +83,8 @@ private sealed class GlobalJsonTestNode
[JsonPropertyName("runner")]
public string RunnerName { get; set; } = null!;
}

[JsonSourceGenerationOptions(ReadCommentHandling = JsonCommentHandling.Skip)]
[JsonSerializable(typeof(GlobalJsonModel))]
private partial class GlobalJsonSerializerContext : JsonSerializerContext;
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private void PrintJson(IEnumerable<IToolPackage> packageEnumerable)
Commands = [p.Command.Name.Value]
})]
};
var jsonText = System.Text.Json.JsonSerializer.Serialize(jsonData, JsonHelper.NoEscapeSerializerOptions);
var jsonText = System.Text.Json.JsonSerializer.Serialize(jsonData, JsonHelper.JsonContext.VersionedDataContractToolListJsonContractArray);
_reporter.WriteLine(jsonText);
}
}
14 changes: 9 additions & 5 deletions src/Cli/dotnet/Commands/Tool/List/ToolListJsonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal sealed class VersionedDataContract<TContract>
/// </summary>
[JsonPropertyName("version")]
public int Version { get; init; } = 1;

[JsonPropertyName("data")]
public required TContract Data { get; init; }
}
Expand All @@ -24,10 +24,10 @@ internal class ToolListJsonContract
{
[JsonPropertyName("packageId")]
public required string PackageId { get; init; }

[JsonPropertyName("version")]
public required string Version { get; init; }

[JsonPropertyName("commands")]
public required string[] Commands { get; init; }
}
Expand All @@ -46,8 +46,12 @@ internal enum ToolListOutputFormat

internal static class JsonHelper
{
public static readonly JsonSerializerOptions NoEscapeSerializerOptions = new()
public static readonly ToolListJsonSerializerContext JsonContext = new(new JsonSerializerOptions()
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
});
}

[JsonSerializable(typeof(VersionedDataContract<ToolListJsonContract[]>))]
[JsonSerializable(typeof(VersionedDataContract<LocalToolListJsonContract[]>))]
internal partial class ToolListJsonSerializerContext : JsonSerializerContext;
2 changes: 1 addition & 1 deletion src/Cli/dotnet/Commands/Tool/List/ToolListLocalCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private void PrintJson(IEnumerable<(ToolManifestPackage toolManifestPackage, Fil
Manifest = p.SourceManifest.Value
})]
};
var jsonText = System.Text.Json.JsonSerializer.Serialize(jsonData, JsonHelper.NoEscapeSerializerOptions);
var jsonText = System.Text.Json.JsonSerializer.Serialize(jsonData, JsonHelper.JsonContext.VersionedDataContractLocalToolListJsonContractArray);
_reporter.WriteLine(jsonText);
}
}
Loading