Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser for actual MSBuild Property option syntax #27086

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<SystemCommandLineVersion>2.0.0-beta4.22363.1</SystemCommandLineVersion>
<MicrosoftDeploymentDotNetReleasesVersion>1.0.0-preview5.1.22263.1</MicrosoftDeploymentDotNetReleasesVersion>
<MicrosoftVisualStudioSetupConfigurationInteropVersion>3.0.4496</MicrosoftVisualStudioSetupConfigurationInteropVersion>
<SpracheVersion>2.3.1</SpracheVersion>
</PropertyGroup>
<PropertyGroup>
<!-- Dependencies from https://github.com/dotnet/runtime -->
Expand Down
38 changes: 37 additions & 1 deletion src/Cli/dotnet/OptionForwardingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.CommandLine.Help;
using System.CommandLine.Parsing;
using System.Linq;
using Sprache;

namespace Microsoft.DotNet.Cli
{
Expand All @@ -18,10 +19,45 @@ public static class OptionForwardingExtensions

public static ForwardedOption<T> ForwardAsSingle<T>(this ForwardedOption<T> option, Func<T, string> format) => option.SetForwardingFunction(format);

private static Parser<(string key, string value)[]> KeyValueParser {
get {
bool IsValidMSBuildPropertyChar (char c) => Char.IsLetterOrDigit(c) || (c == '_') || (c == '-');
baronfel marked this conversation as resolved.
Show resolved Hide resolved
var keyParser =
Parse.Char(IsValidMSBuildPropertyChar, "Any alphanumeric character or '_'").AtLeastOnce().Text().Named("key");

var unquotedValueParser = Parse.CharExcept('"').Named("unquoted value");

var quoteParser = Parse.Char('"').Named("quote");
var semiParser = Parse.Char(';').Named("tick");
var quotedValueParser =
Parse.Contained(unquotedValueParser.AtLeastOnce(), quoteParser, quoteParser).Text().Select(s => $"\"{s}\"").Named("quoted value");
var valueParser =
Parse.XOr(quotedValueParser, Parse.CharExcept(';').AtLeastOnce().Text()).Named("value");
var keyValueParser =
from key in keyParser
from _equals in Parse.Char('=')
from value in valueParser
select (key, value);
var semiOrCommaParser = Parse.Chars(new[]{';', ','});
var keyValues = Parse.DelimitedBy(keyValueParser.Named("key/value"), Parse.Char(';')).Select(pairs => pairs.ToArray()).Named("key/value list");
return keyValues;
baronfel marked this conversation as resolved.
Show resolved Hide resolved
}
}
public static IResult<(string key, string value)[]> ParseKeyValues(string msbuildKeyValue) => KeyValueParser.TryParse(msbuildKeyValue);

public static ForwardedOption<string[]> ForwardAsProperty(this ForwardedOption<string[]> option) => option
.SetForwardingFunction((optionVals) =>
optionVals
.Select(optionVal => optionVal.Replace(";", "%3B")) // must escape semicolon-delimited property values when forwarding them to MSBuild
.Select(ParseKeyValues)
.SelectMany(result => {
baronfel marked this conversation as resolved.
Show resolved Hide resolved
if (result.WasSuccessful && result.Remainder.AtEnd) {
return result.Value;
} else {
return Array.Empty<(string key, string value)>();
}
})
.Select(optionVal => (optionVal.key, value: optionVal.value.Replace(";", "%3B"))) // must escape semicolon-delimited property values when forwarding them to MSBuild
.Select(optionVal => $"{optionVal.key}={optionVal.value}")
.Select(optionVal => $"{option.Aliases.FirstOrDefault()}:{optionVal}")
);

Expand Down
2 changes: 2 additions & 0 deletions src/Cli/dotnet/dotnet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<PackageId>Microsoft.DotNet.Cli</PackageId>
<UseAppHost>false</UseAppHost>
<IsPackable>true</IsPackable>
<NoWarn>$(NoWarn);CS8002</NoWarn>
baronfel marked this conversation as resolved.
Show resolved Hide resolved
</PropertyGroup>
<ItemGroup>
<Compile Remove="commands\dotnet-new\**" />
Expand Down Expand Up @@ -95,6 +96,7 @@
<PackageReference Include="Microsoft.Deployment.DotNet.Releases" Version="$(MicrosoftDeploymentDotNetReleasesVersion)" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="$(SystemServiceProcessServiceControllerVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Version="$(MicrosoftVisualStudioSetupConfigurationInteropVersion)" PrivateAssets="All" ExcludeAssets="Runtime"/>
<PackageReference Include="Sprache" Version="$(SpracheVersion)" />
baronfel marked this conversation as resolved.
Show resolved Hide resolved
</ItemGroup>
<ItemGroup Condition=" '$(IncludeAspNetCoreRuntime)' != 'false' ">
<PackageReference Include="Microsoft.AspNetCore.DeveloperCertificates.XPlat" Version="$(MicrosoftAspNetCoreDeveloperCertificatesXPlatPackageVersion)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public void MSBuildArgumentsAreForwardedCorrectly(string[] arguments, bool build
[InlineData(new string[] { "-p:teamcity_buildConfName=\"Build, Test and Publish\"" }, new string[] { "--property:teamcity_buildConfName=\"Build, Test and Publish\"" })]
[InlineData(new string[] { "-p:prop1=true", "-p:prop2=false" }, new string[] { "--property:prop1=true", "--property:prop2=false" })]
[InlineData(new string[] { "-p:prop1=\".;/opt/usr\"" }, new string[] { "--property:prop1=\".%3B/opt/usr\"" })]
[InlineData(new string[] { "-p:prop1=true;prop2=false;prop3=\"wut\";prop4=\"1;2;3\"" }, new string[]{ "--property:prop1=true", "--property:prop2=false", "--property:prop3=\"wut\"", "--property:prop4=\"1%3B2%3B3\""})]
[InlineData(new string[] { "-p:prop4=\"1;2;3\"" }, new string[]{ "--property:prop4=\"1%3B2%3B3\""})]
[InlineData(new string[] { "-p:prop4=\"1 ;2 ;3 \"" }, new string[]{ "--property:prop4=\"1 %3B2 %3B3 \""})]
public void Can_pass_msbuild_properties_safely(string[] tokens, string[] forwardedTokens) {
nagilson marked this conversation as resolved.
Show resolved Hide resolved
var forwardingFunction = (CommonOptions.PropertiesOption as ForwardedOption<string[]>).GetForwardingFunction();
var result = CommonOptions.PropertiesOption.Parse(tokens);
Expand Down