Remove dependency on Microsoft.DotNet.Cli.Utils from dotnet-user-secrets

This commit is contained in:
Nate McMaster 2016-11-21 13:06:44 -08:00
parent 46136e91ab
commit 4a64ef857c
No known key found for this signature in database
GPG Key ID: BD729980AA6A21BD
14 changed files with 162 additions and 145 deletions

View File

@ -30,7 +30,7 @@ namespace Microsoft.DotNet.Watcher
public static int Main(string[] args)
{
HandleDebugSwitch(ref args);
DebugHelper.HandleDebugSwitch(ref args);
return new Program(PhysicalConsole.Singleton, Directory.GetCurrentDirectory())
.RunAsync(args)
.GetAwaiter()
@ -141,17 +141,5 @@ namespace Microsoft.DotNet.Watcher
return LogLevel.Information;
}
[Conditional("DEBUG")]
private static void HandleDebugSwitch(ref string[] args)
{
if (args.Length > 0 && string.Equals("--debug", args[0], StringComparison.OrdinalIgnoreCase))
{
args = args.Skip(1).ToArray();
Console.WriteLine("Waiting for debugger to attach. Press ENTER to continue");
Console.WriteLine($"Process ID: {Process.GetCurrentProcess().Id}");
Console.ReadLine();
}
}
}
}

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Tools.Internal;
@ -37,7 +36,7 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
var optionProject = app.Option("-p|--project <PROJECT>", "Path to project, default is current directory",
CommandOptionType.SingleValue, inherited: true);
var optionConfig = app.Option("-c|--configuration <CONFIGURATION>", $"The project configuration to use. Defaults to {Constants.DefaultConfiguration}",
var optionConfig = app.Option("-c|--configuration <CONFIGURATION>", $"The project configuration to use. Defaults to 'Debug'",
CommandOptionType.SingleValue, inherited: true);
// the escape hatch if project evaluation fails, or if users want to alter a secret store other than the one
@ -47,8 +46,8 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
var options = new CommandLineOptions();
app.Command("set", c => SetCommand.Configure(c, options));
app.Command("remove", c => RemoveCommand.Configure(c, options));
app.Command("set", c => SetCommand.Configure(c, options, console));
app.Command("remove", c => RemoveCommand.Configure(c, options, console));
app.Command("list", c => ListCommand.Configure(c, options));
app.Command("clear", c => ClearCommand.Configure(c, options));

View File

@ -1,10 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.Tools.Internal;
namespace Microsoft.Extensions.SecretManager.Tools.Internal
@ -37,12 +36,12 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
if (projects.Count > 1)
{
throw new GracefulException(Resources.FormatError_MultipleProjectsFound(projectPath));
throw new FileNotFoundException(Resources.FormatError_MultipleProjectsFound(projectPath));
}
if (projects.Count == 0)
{
throw new GracefulException(Resources.FormatError_NoProjectsFound(projectPath));
throw new FileNotFoundException(Resources.FormatError_NoProjectsFound(projectPath));
}
return projects[0];
@ -50,7 +49,7 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
if (!File.Exists(projectPath))
{
throw new GracefulException(Resources.FormatError_ProjectPath_NotFound(projectPath));
throw new FileNotFoundException(Resources.FormatError_ProjectPath_NotFound(projectPath));
}
return projectPath;

View File

@ -3,11 +3,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Tools.Internal;
namespace Microsoft.Extensions.SecretManager.Tools.Internal
{
@ -24,7 +25,7 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
_logger = logger;
}
public string Resolve(string project, string configuration = Constants.DefaultConfiguration)
public string Resolve(string project, string configuration = "Debug")
{
var finder = new MsBuildProjectFinder(_workingDirectory);
var projectFile = finder.FindMsBuildProject(project);
@ -35,32 +36,37 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
var outputFile = Path.GetTempFileName();
_tempFiles.Add(outputFile);
var commandOutput = new List<string>();
var commandResult = Command.CreateDotNet("msbuild",
new[] {
targetFile,
"/nologo",
"/t:_FindUserSecretsProperty",
$"/p:Project={projectFile}",
$"/p:OutputFile={outputFile}",
$"/p:Configuration={configuration}"
})
.CaptureStdErr()
.CaptureStdOut()
.OnErrorLine(l => commandOutput.Add(l))
.OnOutputLine(l => commandOutput.Add(l))
.Execute();
if (commandResult.ExitCode != 0)
var args = new[]
{
_logger.LogDebug(string.Join(Environment.NewLine, commandOutput));
throw new GracefulException(Resources.FormatError_ProjectFailedToLoad(projectFile));
"msbuild",
targetFile,
"/nologo",
"/t:_FindUserSecretsProperty",
$"/p:Project={projectFile}",
$"/p:OutputFile={outputFile}",
$"/p:Configuration={configuration}"
};
var psi = new ProcessStartInfo
{
FileName = DotNetMuxer.MuxerPathOrDefault(),
Arguments = ArgumentEscaper.EscapeAndConcatenate(args),
RedirectStandardOutput = true,
RedirectStandardError = true
};
var process = Process.Start(psi);
process.WaitForExit();
if (process.ExitCode != 0)
{
_logger.LogDebug(process.StandardOutput.ReadToEnd());
_logger.LogDebug(process.StandardError.ReadToEnd());
throw new InvalidOperationException(Resources.FormatError_ProjectFailedToLoad(projectFile));
}
var id = File.ReadAllText(outputFile)?.Trim();
if (string.IsNullOrEmpty(id))
{
throw new GracefulException(Resources.FormatError_ProjectMissingId(projectFile));
throw new InvalidOperationException(Resources.FormatError_ProjectMissingId(projectFile));
}
return id;

View File

@ -1,9 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.DotNet.Cli.Utils;
using System;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Tools.Internal;
namespace Microsoft.Extensions.SecretManager.Tools.Internal
{
@ -11,7 +12,7 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
{
private readonly string _keyName;
public static void Configure(CommandLineApplication command, CommandLineOptions options)
public static void Configure(CommandLineApplication command, CommandLineOptions options, IConsole console)
{
command.Description = "Removes the specified user secret";
command.HelpOption();
@ -21,10 +22,12 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal
{
if (keyArg.Value == null)
{
throw new GracefulException("Missing parameter value for 'name'.\nUse the '--help' flag to see info.");
console.Error.WriteLine(Resources.FormatError_MissingArgument("name").Red());
return 1;
}
options.Command = new RemoveCommand(keyArg.Value);
return 0;
});
}

View File

@ -1,21 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
using System;
using System.IO;
using System.Text;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Tools.Internal;
namespace Microsoft.Extensions.SecretManager.Tools.Internal
{
public class SetCommand : ICommand
public class SetCommand
{
private readonly string _keyName;
private readonly string _keyValue;
public static void Configure(CommandLineApplication command, CommandLineOptions options)
public static void Configure(CommandLineApplication command, CommandLineOptions options, IConsole console)
{
command.Description = "Sets the user secret to the specified value";
command.ExtendedHelpText = @"
@ -34,72 +31,74 @@ Examples:
command.OnExecute(() =>
{
options.Command = new SetCommand(nameArg.Value, valueArg.Value);
if (console.IsInputRedirected && nameArg.Value == null)
{
options.Command = new FromStdInStrategy();
return 0;
}
if (string.IsNullOrEmpty(nameArg.Value))
{
console.Error.WriteLine(Resources.FormatError_MissingArgument("name").Red());
return 1;
}
if (valueArg.Value == null)
{
console.Error.WriteLine(Resources.FormatError_MissingArgument("value").Red());
return 1;
}
options.Command = new ForOneValueStrategy(nameArg.Value, valueArg.Value);
return 0;
});
}
internal SetCommand(string keyName, string keyValue)
public class FromStdInStrategy : ICommand
{
Debug.Assert(keyName != null || keyValue == null, "Inconsistent state. keyValue must not be null if keyName is null.");
_keyName = keyName;
_keyValue = keyValue;
}
internal SetCommand()
{ }
public void Execute(CommandContext context)
{
if (context.Console.IsInputRedirected && _keyName == null)
public void Execute(CommandContext context)
{
ReadFromInput(context);
}
else
{
SetFromArguments(context);
}
}
private void ReadFromInput(CommandContext context)
{
// parses stdin with the same parser that Microsoft.Extensions.Configuration.Json would use
var provider = new ReadableJsonConfigurationProvider();
using (var stream = new MemoryStream())
{
using (var writer = new StreamWriter(stream, Encoding.Unicode, 1024, true))
// parses stdin with the same parser that Microsoft.Extensions.Configuration.Json would use
var provider = new ReadableJsonConfigurationProvider();
using (var stream = new MemoryStream())
{
writer.Write(context.Console.In.ReadToEnd()); // TODO buffer?
using (var writer = new StreamWriter(stream, Encoding.Unicode, 1024, true))
{
writer.Write(context.Console.In.ReadToEnd()); // TODO buffer?
}
stream.Seek(0, SeekOrigin.Begin);
provider.Load(stream);
}
stream.Seek(0, SeekOrigin.Begin);
provider.Load(stream);
foreach (var k in provider.CurrentData)
{
context.SecretStore.Set(k.Key, k.Value);
}
context.Logger.LogInformation(Resources.Message_Saved_Secrets, provider.CurrentData.Count);
context.SecretStore.Save();
}
foreach (var k in provider.CurrentData)
{
context.SecretStore.Set(k.Key, k.Value);
}
context.Logger.LogInformation(Resources.Message_Saved_Secrets, provider.CurrentData.Count);
context.SecretStore.Save();
}
private void SetFromArguments(CommandContext context)
public class ForOneValueStrategy : ICommand
{
if (_keyName == null)
private readonly string _keyName;
private readonly string _keyValue;
public ForOneValueStrategy(string keyName, string keyValue)
{
throw new GracefulException(Resources.FormatError_MissingArgument("name"));
_keyName = keyName;
_keyValue = keyValue;
}
if (_keyValue == null)
public void Execute(CommandContext context)
{
throw new GracefulException((Resources.FormatError_MissingArgument("value")));
context.SecretStore.Set(_keyName, _keyValue);
context.SecretStore.Save();
context.Logger.LogInformation(Resources.Message_Saved_Secret, _keyName, _keyValue);
}
context.SecretStore.Set(_keyName, _keyValue);
context.SecretStore.Save();
context.Logger.LogInformation(Resources.Message_Saved_Secret, _keyName, _keyValue);
}
}
}

View File

@ -16,10 +16,9 @@
<dependencies>
<group targetFramework=".NETCoreApp1.0">
<!-- MUST BE alphabetical -->
<dependency id="Microsoft.DotNet.Cli.Utils" version="$dep_1$" />
<dependency id="Microsoft.Extensions.Configuration.UserSecrets" version="$dep_2$" />
<dependency id="Microsoft.Extensions.Logging" version="$dep_3$" />
<dependency id="Microsoft.NETCore.App" version="$dep_4$" />
<dependency id="Microsoft.Extensions.Configuration.UserSecrets" version="$dep_1$" />
<dependency id="Microsoft.Extensions.Logging" version="$dep_2$" />
<dependency id="Microsoft.NETCore.App" version="$dep_3$" />
</group>
</dependencies>
</metadata>

View File

@ -3,7 +3,6 @@
using System;
using System.IO;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.SecretManager.Tools.Internal;
using Microsoft.Extensions.Tools.Internal;
@ -58,20 +57,8 @@ namespace Microsoft.Extensions.SecretManager.Tools
}
catch (Exception exception)
{
if (exception is GracefulException)
{
if (exception.InnerException != null)
{
Logger.LogInformation(exception.InnerException.Message);
}
Logger.LogError(exception.Message);
}
else
{
Logger.LogDebug(exception.ToString());
Logger.LogCritical(Resources.Error_Command_Failed, exception.Message);
}
Logger.LogDebug(exception.ToString());
Logger.LogCritical(Resources.Error_Command_Failed, exception.Message);
returnCode = 1;
return false;
}
@ -96,7 +83,17 @@ namespace Microsoft.Extensions.SecretManager.Tools
CommandOutputProvider.LogLevel = LogLevel.Debug;
}
var userSecretsId = ResolveId(options);
string userSecretsId;
try
{
userSecretsId = ResolveId(options);
}
catch (Exception ex) when (ex is InvalidOperationException || ex is FileNotFoundException)
{
_logger.LogError(ex.Message);
return 1;
}
var store = new SecretsStore(userSecretsId, Logger);
var context = new Internal.CommandContext(store, Logger, _console);
options.Command.Execute(context);

View File

@ -38,7 +38,6 @@
]
},
"dependencies": {
"Microsoft.DotNet.Cli.Utils": "1.0.0-preview3-004056",
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.NETCore.App": {

24
src/Shared/DebugHelper.cs Normal file
View File

@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.Linq;
namespace Microsoft.Extensions.Tools.Internal
{
public static class DebugHelper
{
[Conditional("DEBUG")]
public static void HandleDebugSwitch(ref string[] args)
{
if (args.Length > 0 && string.Equals("--debug", args[0], StringComparison.OrdinalIgnoreCase))
{
args = args.Skip(1).ToArray();
Console.WriteLine("Waiting for debugger to attach. Press ENTER to continue");
Console.WriteLine($"Process ID: {Process.GetCurrentProcess().Id}");
Console.ReadLine();
}
}
}
}

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.SecretManager.Tools.Internal;
using Xunit;
@ -34,7 +33,7 @@ namespace Microsoft.Extensions.SecretsManager.Tools.Tests
{
var finder = new MsBuildProjectFinder(files.Root);
Assert.Throws<GracefulException>(() => finder.FindMsBuildProject(null));
Assert.Throws<FileNotFoundException>(() => finder.FindMsBuildProject(null));
}
}
@ -46,7 +45,7 @@ namespace Microsoft.Extensions.SecretsManager.Tools.Tests
var finder = new MsBuildProjectFinder(files.Root);
files.Add("test.xproj", "");
Assert.Throws<GracefulException>(() => finder.FindMsBuildProject(null));
Assert.Throws<FileNotFoundException>(() => finder.FindMsBuildProject(null));
}
}
@ -59,7 +58,7 @@ namespace Microsoft.Extensions.SecretsManager.Tools.Tests
files.Add("Test2.csproj", "");
var finder = new MsBuildProjectFinder(files.Root);
Assert.Throws<GracefulException>(() => finder.FindMsBuildProject(null));
Assert.Throws<FileNotFoundException>(() => finder.FindMsBuildProject(null));
}
}
@ -70,7 +69,7 @@ namespace Microsoft.Extensions.SecretsManager.Tools.Tests
{
var finder = new MsBuildProjectFinder(files.Root);
Assert.Throws<GracefulException>(() => finder.FindMsBuildProject("test.csproj"));
Assert.Throws<FileNotFoundException>(() => finder.FindMsBuildProject("test.csproj"));
}
}
@ -80,7 +79,7 @@ namespace Microsoft.Extensions.SecretsManager.Tools.Tests
var files = new TemporaryFileProvider();
var finder = new MsBuildProjectFinder(files.Root);
files.Dispose();
Assert.Throws<GracefulException>(() => finder.FindMsBuildProject(null));
Assert.Throws<FileNotFoundException>(() => finder.FindMsBuildProject(null));
}
}
}

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.Configuration.UserSecrets;
using Microsoft.Extensions.Configuration.UserSecrets.Tests;
using Microsoft.Extensions.Logging;
@ -44,8 +43,8 @@ namespace Microsoft.Extensions.SecretManager.Tools.Tests
var project = Path.Combine(_fixture.CreateProject(id), "TestProject.csproj");
var secretManager = CreateProgram();
var ex = Assert.Throws<GracefulException>(() => secretManager.RunInternal("list", "-p", project));
Assert.Equal(Resources.FormatError_ProjectMissingId(project), ex.Message);
secretManager.RunInternal("list", "-p", project);
Assert.Contains(Resources.FormatError_ProjectMissingId(project), _logger.Messages);
}
[Fact]
@ -54,8 +53,8 @@ namespace Microsoft.Extensions.SecretManager.Tools.Tests
var project = Path.Combine(_fixture.CreateProject("<"), "TestProject.csproj");
var secretManager = CreateProgram();
var ex = Assert.Throws<GracefulException>(() => secretManager.RunInternal("list", "-p", project));
Assert.Equal(Resources.FormatError_ProjectFailedToLoad(project), ex.Message);
secretManager.RunInternal("list", "-p", project);
Assert.Contains(Resources.FormatError_ProjectFailedToLoad(project), _logger.Messages);
}
[Fact]
@ -64,8 +63,8 @@ namespace Microsoft.Extensions.SecretManager.Tools.Tests
var projectPath = Path.Combine(_fixture.GetTempSecretProject(), "does_not_exist", "TestProject.csproj");
var secretManager = CreateProgram();
var ex = Assert.Throws<GracefulException>(() => secretManager.RunInternal("list", "--project", projectPath));
Assert.Equal(Resources.FormatError_ProjectPath_NotFound(projectPath), ex.Message);
secretManager.RunInternal("list", "--project", projectPath);
Assert.Contains(Resources.FormatError_ProjectPath_NotFound(projectPath), _logger.Messages);
}
[Fact]

View File

@ -37,7 +37,7 @@ namespace Microsoft.Extensions.SecretManager.Tools.Tests
In = new StringReader(input)
};
var secretStore = new TestSecretsStore();
var command = new SetCommand();
var command = new SetCommand.FromStdInStrategy();
command.Execute(new CommandContext(secretStore, NullLogger.Instance, testConsole));
@ -64,7 +64,7 @@ namespace Microsoft.Extensions.SecretManager.Tools.Tests
In = new StringReader(input)
};
var secretStore = new TestSecretsStore();
var command = new SetCommand();
var command = new SetCommand.FromStdInStrategy();
command.Execute(new CommandContext(secretStore, NullLogger.Instance, testConsole));
@ -83,12 +83,8 @@ namespace Microsoft.Extensions.SecretManager.Tools.Tests
IsInputRedirected = true,
In = new StringReader("")
};
var secretStore = new TestSecretsStore();
var command = new SetCommand("key", null);
var ex = Assert.Throws<Microsoft.DotNet.Cli.Utils.GracefulException>(
() => command.Execute(new CommandContext(secretStore, NullLogger.Instance, testConsole)));
Assert.Equal(Resources.FormatError_MissingArgument("value"), ex.Message);
var options = CommandLineOptions.Parse(new [] { "set", "key", "value" }, testConsole);
Assert.IsType<SetCommand.ForOneValueStrategy>(options.Command);
}
private class TestSecretsStore : SecretsStore

View File

@ -0,0 +1,10 @@
set -e
~/.dotnet/dotnet build
../../.build/dotnet/dotnet exec \
--depsfile bin/Debug/netcoreapp1.0/Microsoft.Extensions.SecretManager.Tools.Tests.deps.json \
--runtimeconfig bin/Debug/netcoreapp1.0/Microsoft.Extensions.SecretManager.Tools.Tests.runtimeconfig.json \
../../.build/dotnet-test-xunit/2.2.0-preview2-build1029/lib/netcoreapp1.0/dotnet-test-xunit.dll \
bin/Debug/netcoreapp1.0/Microsoft.Extensions.SecretManager.Tools.Tests.dll \
$@