Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -511,11 +511,11 @@ dotnet_diagnostic.IDE0040.severity = warning
insert_final_newline = false

# Verify settings
[*.{received,verified}.{txt,xml,json}]
[*.{received,verified}.{txt,xml,json,sh,zsh,nu,fish,ps1}]
charset = "utf-8-bom"
end_of_line = lf
indent_size = unset
indent_style = unset
insert_final_newline = false
tab_width = unset
trim_trailing_whitespace = false
trim_trailing_whitespace = false
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,7 @@
*.verified.txt text eol=lf working-tree-encoding=UTF-8
*.verified.xml text eol=lf working-tree-encoding=UTF-8
*.verified.json text eol=lf working-tree-encoding=UTF-8
*.verified.sh text eol=lf working-tree-encoding=UTF-8
*.verified.zsh text eol=lf working-tree-encoding=UTF-8
*.verified.nu text eol=lf working-tree-encoding=UTF-8
*.verified.fish text eol=lf working-tree-encoding=UTF-8
9 changes: 8 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"dotnet.testWindow.disableAutoDiscovery": true,
"dotnet.defaultSolution": "sdk.slnx"
"dotnet.testWindow.disableBuildOnRun": true,
"dotnet.defaultSolution": "cli.slnf",
"files.associations": {
"*.slnf": "json",
"*.props": "xml",
"*.targets": "xml",
"*.*proj": "xml"
}
}
15 changes: 15 additions & 0 deletions cli.slnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"solution": {
"path": "sdk.slnx",
"projects": [
"src\\BuiltInTools\\dotnet-watch\\dotnet-watch.csproj",
"src\\Cli\\dotnet\\dotnet.csproj",
"src\\Cli\\Microsoft.DotNet.Cli.Utils\\Microsoft.DotNet.Cli.Utils.csproj",
"test\\dotnet-new.IntegrationTests\\dotnet-new.IntegrationTests.csproj",
"test\\dotnet-watch.Tests\\dotnet-watch.Tests.csproj",
"test\\dotnet.Tests\\dotnet.Tests.csproj",
"test\\Microsoft.DotNet.Cli.Utils.Tests\\Microsoft.DotNet.Cli.Utils.Tests.csproj",
"test\\Microsoft.NET.TestFramework\\Microsoft.NET.TestFramework.csproj"
]
}
}
5 changes: 5 additions & 0 deletions src/Cli/Microsoft.DotNet.Cli.Utils/Env.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 System.Diagnostics.CodeAnalysis;

namespace Microsoft.DotNet.Cli.Utils;

public static class Env
Expand All @@ -21,6 +23,9 @@ public static class Env
public static bool GetEnvironmentVariableAsBool(string name, bool defaultValue = false) =>
s_environment.GetEnvironmentVariableAsBool(name, defaultValue);

public static bool TryGetEnvironmentVariableAsBool(string name, [NotNullWhen(true)] out bool value) =>
s_environment.TryGetEnvironmentVariableAsBool(name, out value);

public static int? GetEnvironmentVariableAsNullableInt(string name) =>
s_environment.GetEnvironmentVariableAsNullableInt(name);

Expand Down
60 changes: 60 additions & 0 deletions src/Cli/Microsoft.DotNet.Cli.Utils/EnvironmentProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using Microsoft.DotNet.Cli.Utils.Extensions;

namespace Microsoft.DotNet.Cli.Utils;
Expand Down Expand Up @@ -136,6 +137,12 @@ public bool GetEnvironmentVariableAsBool(string name, bool defaultValue)
return Environment.GetEnvironmentVariable(variable, target);
}

public bool TryGetEnvironmentVariable(string name, [NotNullWhen(true)] out string? value)
{
value = Environment.GetEnvironmentVariable(name);
return value != null;
}

public void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)
{
Environment.SetEnvironmentVariable(variable, value, target);
Expand All @@ -150,4 +157,57 @@ public void SetEnvironmentVariable(string variable, string value, EnvironmentVar

return null;
}

public bool TryGetEnvironmentVariableAsBool(string name, [NotNullWhen(true)] out bool value)
{
if (TryGetEnvironmentVariable(name, out string? strValue) &&
(bool.TryParse(strValue, out bool boolValue)
|| TryParseNonBoolConstantStringAsBool(strValue, out boolValue)))
{
value = boolValue;
return true;
}
else
{
value = false;
return false;
}
}

/// <summary>
/// Parses non-boolean constant strings like "1", "0", "yes", "no", "on", "off" as boolean values.
/// </summary>
private static bool TryParseNonBoolConstantStringAsBool(string? strValue, out bool value)
{
switch (strValue?.ToLowerInvariant())
{
case "1":
case "yes":
case "on":
value = true;
return true;
case "0":
case "no":
case "off":
value = false;
return true;
default:
value = false;
return false;
}
}

public bool TryGetEnvironmentVariableAsInt(string name, [NotNullWhen(true)] out int value)
{
if (TryGetEnvironmentVariable(name, out string? strValue) && int.TryParse(strValue, out int intValue))
{
value = intValue;
return true;
}
else
{
value = -1;
return false;
}
}
}
7 changes: 7 additions & 0 deletions src/Cli/Microsoft.DotNet.Cli.Utils/IEnvironmentProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace Microsoft.DotNet.Cli.Utils;

using System.Diagnostics.CodeAnalysis;


public interface IEnvironmentProvider
{
IEnumerable<string> ExecutableExtensions { get; }
Expand All @@ -19,6 +22,10 @@ public interface IEnvironmentProvider

string? GetEnvironmentVariable(string name);

bool TryGetEnvironmentVariable(string name, [NotNullWhen(true)] out string? value);
bool TryGetEnvironmentVariableAsBool(string name, [NotNullWhen(true)] out bool value);
bool TryGetEnvironmentVariableAsInt(string name, [NotNullWhen(true)] out int value);

string? GetEnvironmentVariable(string variable, EnvironmentVariableTarget target);

void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target);
Expand Down
73 changes: 61 additions & 12 deletions src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ private MSBuildArgs(
string[]? getTargetResult,
string[]? getResultOutputFile,
VerbosityOptions? verbosity,
string[]? otherMSBuildArgs)
bool noLogo,
string[]? otherMSBuildArgs
)
{
GlobalProperties = properties;
RestoreGlobalProperties = restoreProperties;
Expand All @@ -31,6 +33,7 @@ private MSBuildArgs(
GetTargetResult = getTargetResult;
GetResultOutputFile = getResultOutputFile;
Verbosity = verbosity;
NoLogo = noLogo;
OtherMSBuildArgs = otherMSBuildArgs is not null
? [.. otherMSBuildArgs]
: new List<string>();
Expand All @@ -51,16 +54,33 @@ private MSBuildArgs(
/// </summary>
public string[]? RequestedTargets { get; }

/// <summary>
/// If specified, the list of MSBuild Property names to retrieve and report directly for this build of a single project.
/// </summary>
public string[]? GetProperty { get; }

/// <summary>
/// If specified, the list of MSBuild Item names to retrieve and report directly for this build of a single project.
/// </summary>
public string[]? GetItem { get; }

/// <summary>
/// If specified, the list of MSBuild Target Output/Return Items to retrieve and report directly for this build of a single project.
/// </summary>
public string[]? GetTargetResult { get; }

/// <summary>
/// If specified, the list of output files to which to write --getProperty, --getItem, and --getTargetResult outputs.
/// </summary>
public string[]? GetResultOutputFile { get; }

public VerbosityOptions? Verbosity { get; }

/// <summary>
/// Whether or not the MSBuild product header text should be emitted at the start of this build
/// </summary>
public bool NoLogo { get; }

/// <summary>
/// All other arguments that aren't already explicitly modeled by this structure.
/// The main categories of these today are logger configurations
Expand Down Expand Up @@ -89,16 +109,15 @@ public static MSBuildArgs AnalyzeMSBuildArguments(IEnumerable<string> forwardedA
}

var parseResult = fakeCommand.Parse([.. forwardedAndUserFacingArgs], _analysisParsingConfiguration);
var globalProperties = parseResult.GetResult("--property") is OptionResult propResult ? propResult.GetValueOrDefault<ReadOnlyDictionary<string, string>?>() : null;
var restoreProperties = parseResult.GetResult("--restoreProperty") is OptionResult restoreResult ? restoreResult.GetValueOrDefault<ReadOnlyDictionary<string, string>?>() : null;
var requestedTargets = parseResult.GetResult("--target") is OptionResult targetResult ? targetResult.GetValueOrDefault<string[]?>() : null;
var globalProperties = TryGetValue<ReadOnlyDictionary<string, string>?>("--property");
var restoreProperties = TryGetValue<ReadOnlyDictionary<string, string>?>("--restoreProperty");
var requestedTargets = TryGetValue<string[]?>("--target");
var getProperty = TryGetValue<string[]>("--getProperty");
var getItem = TryGetValue<string[]?>("--getItem");
var getTargetResult = TryGetValue<string[]?>("--getTargetResult");
var getResultOutputFile = TryGetValue<string[]?>("--getResultOutputFile");
var verbosity = parseResult.GetResult("--verbosity") is OptionResult verbosityResult
? verbosityResult.GetValueOrDefault<VerbosityOptions?>()
: null;
var verbosity = TryGetValue<VerbosityOptions?>("--verbosity");
var nologo = TryGetValue<bool?>("--no-logo") ?? true; // Default to nologo if not specified
var otherMSBuildArgs = parseResult.UnmatchedTokens.ToArray();
return new MSBuildArgs(
properties: globalProperties,
Expand All @@ -109,8 +128,12 @@ public static MSBuildArgs AnalyzeMSBuildArguments(IEnumerable<string> forwardedA
getTargetResult: getTargetResult,
getResultOutputFile: getResultOutputFile,
otherMSBuildArgs: otherMSBuildArgs,
verbosity: verbosity);
verbosity: verbosity,
noLogo: nologo);

/// We can't use <see cref="ParseResult.GetResult(string)"/> to check if the names of the options we care
/// about were specified, because if they weren't specified it throws.
/// So we first check if the option was specified, and only then get its value.
T? TryGetValue<T>(string name)
{
return options.Any(o => o.Name == name) ? parseResult.GetValue<T>(name) : default;
Expand All @@ -120,19 +143,19 @@ public static MSBuildArgs AnalyzeMSBuildArguments(IEnumerable<string> forwardedA

public static MSBuildArgs FromProperties(ReadOnlyDictionary<string, string>? properties)
{
return new MSBuildArgs(properties, null, null, null, null, null, null, null, null);
return new MSBuildArgs(properties, null, null, null, null, null, null, null, noLogo: false, null);
}

public static MSBuildArgs FromOtherArgs(params ReadOnlySpan<string> args)
{
return new MSBuildArgs(null, null, null, null, null, null, null, null, args.ToArray());
return new MSBuildArgs(null, null, null, null, null, null, null, null, noLogo: false, args.ToArray());
}
public static MSBuildArgs FromVerbosity(VerbosityOptions verbosity)
{
return new MSBuildArgs(null, null, null, null, null, null, null, verbosity, null);
return new MSBuildArgs(null, null, null, null, null, null, null, verbosity, noLogo: false, null);
}

public static readonly MSBuildArgs ForHelp = new(null, null, null, null, null, null, null, null, ["--help"]);
public static readonly MSBuildArgs ForHelp = new(null, null, null, null, null, null, null, null, noLogo: true, ["--help"]);

/// <summary>
/// Completely replaces the MSBuild arguments with the provided <paramref name="newArgs"/>.
Expand All @@ -148,6 +171,7 @@ public MSBuildArgs CloneWithExplicitArgs(string[] newArgs)
getTargetResult: GetTargetResult,
getResultOutputFile: GetResultOutputFile,
otherMSBuildArgs: newArgs,
noLogo: NoLogo,
verbosity: Verbosity);
}

Expand All @@ -168,6 +192,7 @@ public MSBuildArgs CloneWithAdditionalArgs(params string[] additionalArgs)
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}

Expand All @@ -180,6 +205,7 @@ public MSBuildArgs CloneWithAdditionalArgs(params string[] additionalArgs)
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
[.. OtherMSBuildArgs, .. additionalArgs]);
}

Expand All @@ -197,6 +223,7 @@ public MSBuildArgs CloneWithAdditionalRestoreProperties(ReadOnlyDictionary<strin
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}
if (RestoreGlobalProperties is null)
Expand All @@ -210,6 +237,7 @@ public MSBuildArgs CloneWithAdditionalRestoreProperties(ReadOnlyDictionary<strin
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}

Expand All @@ -227,6 +255,7 @@ public MSBuildArgs CloneWithAdditionalRestoreProperties(ReadOnlyDictionary<strin
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}

Expand All @@ -244,6 +273,7 @@ public MSBuildArgs CloneWithAdditionalProperties(ReadOnlyDictionary<string, stri
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}
if (GlobalProperties is null)
Expand All @@ -257,6 +287,7 @@ public MSBuildArgs CloneWithAdditionalProperties(ReadOnlyDictionary<string, stri
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}

Expand All @@ -274,6 +305,7 @@ public MSBuildArgs CloneWithAdditionalProperties(ReadOnlyDictionary<string, stri
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}

Expand All @@ -291,6 +323,7 @@ public MSBuildArgs CloneWithAdditionalTargets(params ReadOnlySpan<string> additi
GetTargetResult,
GetResultOutputFile,
Verbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}

Expand All @@ -305,6 +338,22 @@ public MSBuildArgs CloneWithVerbosity(VerbosityOptions newVerbosity)
GetTargetResult,
GetResultOutputFile,
newVerbosity,
NoLogo,
OtherMSBuildArgs.ToArray());
}

public MSBuildArgs CloneWithNoLogo(bool noLogo)
{
return new MSBuildArgs(
GlobalProperties,
RestoreGlobalProperties,
RequestedTargets,
GetProperty,
GetItem,
GetTargetResult,
GetResultOutputFile,
Verbosity,
noLogo,
OtherMSBuildArgs.ToArray());
}

Expand Down
Loading
Loading