Skip to content

Commit 6361c51

Browse files
authored
[automated] Merge branch 'release/10.0.1xx' => 'main' (#50438)
2 parents c68d927 + cb169e3 commit 6361c51

File tree

13 files changed

+198
-46
lines changed

13 files changed

+198
-46
lines changed

documentation/general/dotnet-run-file.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ Additionally, the implicit project file has the following customizations:
3838

3939
- `ArtifactsPath` is set to a [temp directory](#build-outputs).
4040

41-
- `RuntimeHostConfigurationOption`s are set for `EntryPointFilePath` and `EntryPointFileDirectoryPath` which can be accessed in the app via `AppContext`:
41+
- `PublishDir` and `PackageOutputPath` are set to `./artifacts/` so the outputs of `dotnet publish` and `dotnet pack` are next to the file-based app.
42+
43+
- `RuntimeHostConfigurationOption`s are set for `EntryPointFilePath` and `EntryPointFileDirectoryPath` (except for `Publish` and `Pack` targets)
44+
which can be accessed in the app via `AppContext`:
4245

4346
```cs
4447
string? filePath = AppContext.GetData("EntryPointFilePath") as string;
@@ -101,7 +104,7 @@ the compilation consists solely of the single file read from the standard input.
101104

102105
Commands `dotnet restore file.cs` and `dotnet build file.cs` are needed for IDE support and hence work for file-based programs.
103106

104-
Command `dotnet publish file.cs` is also supported for file-based programs.
107+
Commands `dotnet publish file.cs` and `dotnet pack file.cs` are also supported for file-based programs.
105108
Note that file-based apps have implicitly set `PublishAot=true`, so publishing uses Native AOT (and building reports AOT warnings).
106109
To opt out, use `#:property PublishAot=false` directive in your `.cs` file.
107110

@@ -373,7 +376,7 @@ so `dotnet file.cs` instead of `dotnet run file.cs` should be used in shebangs:
373376

374377
### Other possible commands
375378

376-
We can consider supporting other commands like `dotnet pack`, `dotnet watch`,
379+
We can consider supporting other commands like `dotnet watch`,
377380
however the primary scenario is `dotnet run` and we might never support additional commands.
378381

379382
All commands supporting file-based programs should have a way to receive the target path similarly to `dotnet run`,

src/Cli/dotnet/Commands/Pack/PackCommand.cs

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@
44
using System.Collections.ObjectModel;
55
using System.CommandLine;
66
using System.CommandLine.Parsing;
7-
using System.Configuration;
87
using Microsoft.DotNet.Cli.Commands.Build;
98
using Microsoft.DotNet.Cli.Commands.Restore;
9+
using Microsoft.DotNet.Cli.Commands.Run;
1010
using Microsoft.DotNet.Cli.Extensions;
1111
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
1212
using Microsoft.DotNet.Cli.Utils;
1313
using NuGet.Commands;
1414
using NuGet.Common;
1515
using NuGet.Packaging;
16-
using NuGet.Packaging.Core;
1716

1817
namespace Microsoft.DotNet.Cli.Commands.Pack;
1918

@@ -23,33 +22,54 @@ public class PackCommand(
2322
string? msbuildPath = null
2423
) : RestoringCommand(msbuildArgs, noRestore, msbuildPath: msbuildPath)
2524
{
26-
public static PackCommand FromArgs(string[] args, string? msbuildPath = null)
25+
public static CommandBase FromArgs(string[] args, string? msbuildPath = null)
2726
{
2827
var parseResult = Parser.Parse(["dotnet", "pack", ..args]);
2928
return FromParseResult(parseResult, msbuildPath);
3029
}
3130

32-
public static PackCommand FromParseResult(ParseResult parseResult, string? msbuildPath = null)
31+
public static CommandBase FromParseResult(ParseResult parseResult, string? msbuildPath = null)
3332
{
34-
var msbuildArgs = parseResult.OptionValuesToBeForwarded(PackCommandParser.GetCommand()).Concat(parseResult.GetValue(PackCommandParser.SlnOrProjectArgument) ?? []);
35-
36-
ReleasePropertyProjectLocator projectLocator = new(parseResult, MSBuildPropertyNames.PACK_RELEASE,
37-
new ReleasePropertyProjectLocator.DependentCommandOptions(
38-
parseResult.GetValue(PackCommandParser.SlnOrProjectArgument),
39-
parseResult.HasOption(PackCommandParser.ConfigurationOption) ? parseResult.GetValue(PackCommandParser.ConfigurationOption) : null
40-
)
41-
);
42-
43-
bool noRestore = parseResult.HasOption(PackCommandParser.NoRestoreOption) || parseResult.HasOption(PackCommandParser.NoBuildOption);
44-
var parsedMSBuildArgs = MSBuildArgs.AnalyzeMSBuildArguments(
45-
msbuildArgs,
46-
CommonOptions.PropertiesOption,
47-
CommonOptions.RestorePropertiesOption,
48-
PackCommandParser.TargetOption,
49-
PackCommandParser.VerbosityOption);
50-
return new PackCommand(
51-
parsedMSBuildArgs.CloneWithAdditionalProperties(projectLocator.GetCustomDefaultConfigurationValueIfSpecified()),
52-
noRestore,
33+
var args = parseResult.GetValue(PackCommandParser.SlnOrProjectOrFileArgument) ?? [];
34+
35+
LoggerUtility.SeparateBinLogArguments(args, out var binLogArgs, out var nonBinLogArgs);
36+
37+
bool noBuild = parseResult.HasOption(PackCommandParser.NoBuildOption);
38+
39+
bool noRestore = noBuild || parseResult.HasOption(PackCommandParser.NoRestoreOption);
40+
41+
return CommandFactory.CreateVirtualOrPhysicalCommand(
42+
PackCommandParser.GetCommand(),
43+
PackCommandParser.SlnOrProjectOrFileArgument,
44+
(msbuildArgs, appFilePath) => new VirtualProjectBuildingCommand(
45+
entryPointFileFullPath: Path.GetFullPath(appFilePath),
46+
msbuildArgs: msbuildArgs)
47+
{
48+
NoBuild = noBuild,
49+
NoRestore = noRestore,
50+
NoCache = true,
51+
},
52+
(msbuildArgs, msbuildPath) =>
53+
{
54+
ReleasePropertyProjectLocator projectLocator = new(parseResult, MSBuildPropertyNames.PACK_RELEASE,
55+
new ReleasePropertyProjectLocator.DependentCommandOptions(
56+
nonBinLogArgs,
57+
parseResult.HasOption(PackCommandParser.ConfigurationOption) ? parseResult.GetValue(PackCommandParser.ConfigurationOption) : null
58+
)
59+
);
60+
return new PackCommand(
61+
msbuildArgs.CloneWithAdditionalProperties(projectLocator.GetCustomDefaultConfigurationValueIfSpecified()),
62+
noRestore,
63+
msbuildPath);
64+
},
65+
optionsToUseWhenParsingMSBuildFlags:
66+
[
67+
CommonOptions.PropertiesOption,
68+
CommonOptions.RestorePropertiesOption,
69+
PackCommandParser.TargetOption,
70+
PackCommandParser.VerbosityOption,
71+
],
72+
parseResult,
5373
msbuildPath);
5474
}
5575

@@ -67,7 +87,7 @@ private static LogLevel MappingVerbosityToNugetLogLevel(VerbosityOptions? verbos
6787

6888
public static int RunPackCommand(ParseResult parseResult)
6989
{
70-
var args = parseResult.GetValue(PackCommandParser.SlnOrProjectArgument)?.ToList() ?? new List<string>();
90+
var args = parseResult.GetValue(PackCommandParser.SlnOrProjectOrFileArgument)?.ToList() ?? new List<string>();
7191

7292
if (args.Count != 1)
7393
{
@@ -112,7 +132,7 @@ public static int Run(ParseResult parseResult)
112132
parseResult.HandleDebugSwitch();
113133
parseResult.ShowHelpOrErrorIfAppropriate();
114134

115-
var args = parseResult.GetValue(PackCommandParser.SlnOrProjectArgument)?.ToList() ?? new List<string>();
135+
var args = parseResult.GetValue(PackCommandParser.SlnOrProjectOrFileArgument)?.ToList() ?? new List<string>();
116136

117137
if (args.Count > 0 && Path.GetExtension(args[0]).Equals(".nuspec", StringComparison.OrdinalIgnoreCase))
118138
{

src/Cli/dotnet/Commands/Pack/PackCommandParser.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,21 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Collections.ObjectModel;
54
using System.CommandLine;
65
using Microsoft.DotNet.Cli.Commands.Build;
76
using Microsoft.DotNet.Cli.Commands.Restore;
87
using Microsoft.DotNet.Cli.Extensions;
9-
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
10-
using NuGet.Commands;
11-
using NuGet.Common;
128
using NuGet.Versioning;
13-
using static Microsoft.DotNet.Cli.Commands.Run.CSharpDirective;
149

1510
namespace Microsoft.DotNet.Cli.Commands.Pack;
1611

1712
internal static class PackCommandParser
1813
{
1914
public static readonly string DocsLink = "https://aka.ms/dotnet-pack";
2015

21-
public static readonly Argument<IEnumerable<string>> SlnOrProjectArgument = new(CliStrings.SolutionOrProjectArgumentName)
16+
public static readonly Argument<string[]> SlnOrProjectOrFileArgument = new(CliStrings.SolutionOrProjectOrFileArgumentName)
2217
{
23-
Description = CliStrings.SolutionOrProjectArgumentDescription,
18+
Description = CliStrings.SolutionOrProjectOrFileArgumentDescription,
2419
Arity = ArgumentArity.ZeroOrMore
2520
};
2621

@@ -97,7 +92,7 @@ private static Command ConstructCommand()
9792
{
9893
var command = new DocumentedCommand("pack", DocsLink, CliCommandStrings.PackAppFullName);
9994

100-
command.Arguments.Add(SlnOrProjectArgument);
95+
command.Arguments.Add(SlnOrProjectOrFileArgument);
10196
command.Options.Add(OutputOption);
10297
command.Options.Add(CommonOptions.ArtifactsPathOption);
10398
command.Options.Add(NoBuildOption);

src/Cli/dotnet/Commands/Publish/PublishCommand.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ public static CommandBase FromParseResult(ParseResult parseResult, string? msbui
3737
CommonOptions.ValidateSelfContainedOptions(parseResult.HasOption(PublishCommandParser.SelfContainedOption),
3838
parseResult.HasOption(PublishCommandParser.NoSelfContainedOption));
3939

40-
var forwardedOptions = parseResult.OptionValuesToBeForwarded(PublishCommandParser.GetCommand());
41-
4240
bool noBuild = parseResult.HasOption(PublishCommandParser.NoBuildOption);
4341

4442
bool noRestore = noBuild || parseResult.HasOption(PublishCommandParser.NoRestoreOption);

src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ ProjectRootElement CreateProjectRootElement(ProjectCollection projectCollection)
753753
isVirtualProject: true,
754754
targetFilePath: EntryPointFileFullPath,
755755
artifactsPath: ArtifactsPath,
756-
includeRuntimeConfigInformation: !MSBuildArgs.RequestedTargets?.Contains("Publish") ?? true);
756+
includeRuntimeConfigInformation: MSBuildArgs.RequestedTargets?.ContainsAny("Publish", "Pack") != true);
757757
var projectFileText = projectFileWriter.ToString();
758758

759759
using var reader = new StringReader(projectFileText);
@@ -858,6 +858,7 @@ public static void WriteProjectFile(
858858
<IncludeProjectNameInArtifactsPaths>false</IncludeProjectNameInArtifactsPaths>
859859
<ArtifactsPath>{EscapeValue(artifactsPath)}</ArtifactsPath>
860860
<PublishDir>artifacts/$(MSBuildProjectName)</PublishDir>
861+
<PackageOutputPath>artifacts/$(MSBuildProjectName)</PackageOutputPath>
861862
<FileBasedProgram>true</FileBasedProgram>
862863
</PropertyGroup>
863864

src/Cli/dotnet/Program.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,18 @@ internal static int ProcessArgs(string[] args, TimeSpan startupTime)
230230
}
231231
PerformanceLogEventSource.Log.TelemetrySaveIfEnabledStart();
232232
performanceData.Add("Startup Time", startupTime.TotalMilliseconds);
233-
TelemetryEventEntry.SendFiltered(Tuple.Create(parseResult, performanceData));
233+
234+
string globalJsonState = string.Empty;
235+
if (TelemetryClient.Enabled)
236+
{
237+
// Get the global.json state to report in telemetry along with this command invocation.
238+
// We don't care about the actual SDK resolution, just the global.json information,
239+
// so just pass empty string as executable directory for resolution.
240+
NativeWrapper.SdkResolutionResult result = NativeWrapper.NETCoreSdkResolverNativeWrapper.ResolveSdk(string.Empty, Environment.CurrentDirectory);
241+
globalJsonState = result.GlobalJsonState;
242+
}
243+
244+
TelemetryEventEntry.SendFiltered(Tuple.Create(parseResult, performanceData, globalJsonState));
234245
PerformanceLogEventSource.Log.TelemetrySaveIfEnabledStop();
235246

236247
int exitCode;

src/Cli/dotnet/Telemetry/TelemetryFilter.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,40 @@ public IEnumerable<ApplicationInsightsEntryFormat> Filter(object objectToFilter)
2626
{
2727
var result = new List<ApplicationInsightsEntryFormat>();
2828
Dictionary<string, double> measurements = null;
29+
string globalJsonState = string.Empty;
2930
if (objectToFilter is Tuple<ParseResult, Dictionary<string, double>> parseResultWithMeasurements)
3031
{
3132
objectToFilter = parseResultWithMeasurements.Item1;
3233
measurements = parseResultWithMeasurements.Item2;
3334
measurements = RemoveZeroTimes(measurements);
3435
}
36+
else if (objectToFilter is Tuple<ParseResult, Dictionary<string, double>, string> parseResultWithMeasurementsAndGlobalJsonState)
37+
{
38+
objectToFilter = parseResultWithMeasurementsAndGlobalJsonState.Item1;
39+
measurements = parseResultWithMeasurementsAndGlobalJsonState.Item2;
40+
measurements = RemoveZeroTimes(measurements);
41+
globalJsonState = parseResultWithMeasurementsAndGlobalJsonState.Item3;
42+
}
3543

3644
if (objectToFilter is ParseResult parseResult)
3745
{
3846
var topLevelCommandName = parseResult.RootSubCommandResult();
3947
if (topLevelCommandName != null)
4048
{
49+
Dictionary<string, string> properties = new()
50+
{
51+
["verb"] = topLevelCommandName
52+
};
53+
if (!string.IsNullOrEmpty(globalJsonState))
54+
{
55+
properties["globalJson"] = globalJsonState;
56+
}
57+
4158
result.Add(new ApplicationInsightsEntryFormat(
4259
"toplevelparser/command",
43-
new Dictionary<string, string>()
44-
{{ "verb", topLevelCommandName }}
45-
, measurements
46-
));
60+
properties,
61+
measurements
62+
));
4763

4864
LogVerbosityForAllTopLevelCommand(result, parseResult, topLevelCommandName, measurements);
4965

src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ internal enum hostfxr_resolve_sdk2_result_key_t : int
8080
resolved_sdk_dir = 0,
8181
global_json_path = 1,
8282
requested_version = 2,
83+
global_json_state = 3,
8384
}
8485

8586
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

src/Resolvers/Microsoft.DotNet.NativeWrapper/SdkResolutionResult.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public class SdkResolutionResult
2020
/// </summary>
2121
public string? RequestedVersion;
2222

23+
/// <summary>
24+
/// Result of the global.json search
25+
/// </summary>
26+
public string? GlobalJsonState;
27+
2328
/// <summary>
2429
/// True if a global.json was found but there was no compatible SDK, so it was ignored.
2530
/// </summary>
@@ -38,6 +43,9 @@ internal void Initialize(Interop.hostfxr_resolve_sdk2_result_key_t key, string v
3843
case Interop.hostfxr_resolve_sdk2_result_key_t.requested_version:
3944
RequestedVersion = value;
4045
break;
46+
case Interop.hostfxr_resolve_sdk2_result_key_t.global_json_state:
47+
GlobalJsonState = value;
48+
break;
4149
}
4250
}
4351
}

test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetPackInvocation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void MsbuildInvocationIsCorrect(string[] args, string[] expectedAdditiona
4141
.ToArray();
4242

4343
var msbuildPath = "<msbuildpath>";
44-
var command = PackCommand.FromArgs(args, msbuildPath);
44+
var command = (PackCommand)PackCommand.FromArgs(args, msbuildPath);
4545
var expectedPrefix = args.FirstOrDefault() == "--no-build" ? ExpectedNoBuildPrefix : [.. ExpectedPrefix, .. GivenDotnetBuildInvocation.RestoreExpectedPrefixForImplicitRestore];
4646

4747
command.SeparateRestoreCommand.Should().BeNull();

0 commit comments

Comments
 (0)