src/NuGet.Clients/NuGet.CommandLine/Common/Console.cs (384 lines of code) (raw):
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security;
using System.Threading.Tasks;
using NuGet.Common;
namespace NuGet.CommandLine
{
public class Console : LoggerBase, IConsole
{
/// <summary>
/// All operations writing to Out should be wrapped in a lock to
/// avoid color mismatches during parallel operations.
/// </summary>
private readonly static object _writerLock = new object();
[System.Runtime.InteropServices.DllImport("libc", EntryPoint = "isatty")]
extern static int _isatty(int fd);
public Console()
{
// setup CancelKeyPress handler so that the console colors are
// restored to their original values when nuget.exe is interrupted
// by Ctrl-C.
var originalForegroundColor = System.Console.ForegroundColor;
var originalBackgroundColor = System.Console.BackgroundColor;
System.Console.CancelKeyPress += (sender, e) =>
{
System.Console.ForegroundColor = originalForegroundColor;
System.Console.BackgroundColor = originalBackgroundColor;
};
}
public int CursorLeft
{
get
{
if (MockCursorLeft != null)
{
return (int)MockCursorLeft;
}
try
{
return System.Console.CursorLeft;
}
catch (IOException)
{
return 0;
}
}
set
{
System.Console.CursorLeft = value;
}
}
public int WindowWidth
{
get
{
if (MockWindowWidth != null)
{
return (int)MockWindowWidth;
}
try
{
var width = System.Console.WindowWidth;
if (width > 0)
{
return width;
}
else
{
// This happens when redirecting output to a file, on
// Linux and OS X (running with Mono).
return int.MaxValue;
}
}
catch (IOException)
{
// probably means redirected to file
return int.MaxValue;
}
}
set
{
System.Console.WindowWidth = value;
}
}
internal int? MockWindowWidth { get; set; }
internal int? MockCursorLeft { get; set; }
private Verbosity _verbosity;
public Verbosity Verbosity
{
get
{
return _verbosity;
}
set
{
_verbosity = value;
VerbosityLevel = GetVerbosityLevel(_verbosity);
}
}
public bool IsNonInteractive
{
get; set;
}
private TextWriter Out
{
get { return Verbosity == Verbosity.Quiet ? TextWriter.Null : System.Console.Out; }
}
public void Write(object value)
{
lock (_writerLock)
{
Out.Write(value);
}
}
public void Write(string value)
{
lock (_writerLock)
{
Out.Write(value);
}
}
public void Write(string format, params object[] args)
{
lock (_writerLock)
{
if (args == null || !args.Any())
{
// Don't try to format strings that do not have arguments. We end up throwing if the original string was not meant to be a format token
// and contained braces (for instance html)
Out.Write(format);
}
else
{
Out.Write(format, args);
}
}
}
public void WriteLine()
{
lock (_writerLock)
{
Out.WriteLine();
}
}
public void WriteLine(object value)
{
lock (_writerLock)
{
Out.WriteLine(value);
}
}
public void WriteLine(string value)
{
lock (_writerLock)
{
Out.WriteLine(value);
}
}
public void WriteLine(string format, params object[] args)
{
lock (_writerLock)
{
Out.WriteLine(format, args);
}
}
public void WriteError(object value)
{
WriteError(value.ToString());
}
public void WriteError(string value)
{
WriteError(value, Array.Empty<object>());
}
public void WriteError(string format, params object[] args)
{
WriteColor(System.Console.Error, ConsoleColor.Red, format, args);
}
public void WriteWarning(string value)
{
WriteWarning(prependWarningText: true, value: value, args: Array.Empty<object>());
}
public void WriteWarning(bool prependWarningText, string value)
{
WriteWarning(prependWarningText, value, Array.Empty<object>());
}
public void WriteWarning(string value, params object[] args)
{
WriteWarning(prependWarningText: true, value: value, args: args);
}
public void WriteWarning(bool prependWarningText, string value, params object[] args)
{
string message = prependWarningText
? String.Format(CultureInfo.CurrentCulture, LocalizedResourceManager.GetString("CommandLine_Warning"), value)
: value;
WriteColor(System.Console.Out, ConsoleColor.Yellow, message, args);
}
public void WriteLine(ConsoleColor color, string value, params object[] args)
{
WriteColor(Out, color, value, args);
}
private static void WriteColor(TextWriter writer, ConsoleColor color, string value, params object[] args)
{
lock (_writerLock)
{
var currentColor = System.Console.ForegroundColor;
try
{
currentColor = System.Console.ForegroundColor;
System.Console.ForegroundColor = color;
if (args == null || !args.Any())
{
// If it doesn't look like something that needs to be formatted, don't format it.
writer.WriteLine(value);
}
else
{
writer.WriteLine(value, args);
}
}
finally
{
System.Console.ForegroundColor = currentColor;
}
}
}
public void PrintJustified(int startIndex, string text)
{
PrintJustified(startIndex, text, WindowWidth);
}
public void PrintJustified(int startIndex, string text, int maxWidth)
{
if (maxWidth > startIndex)
{
maxWidth = maxWidth - startIndex;
}
lock (_writerLock)
{
using (StringReader stringReader = new StringReader(text))
{
string line;
while ((line = stringReader.ReadLine()) != null)
{
// Trim extra whitespace at the beginning and end of the line
line = line.Trim();
if (line == string.Empty)
{
Out.WriteLine();
continue;
}
while (true)
{
// Calculate the number of chars to print based on the width of the System.Console
int length = Math.Min(line.Length, maxWidth);
string content = line.Substring(0, length);
content = content.TrimEnd();
int leftPadding = startIndex + content.Length - CursorLeft;
// Print it with the correct padding
Out.WriteLine((leftPadding > 0) ? content.PadLeft(leftPadding) : content);
line = line.Substring(content.Length).Trim();
if (line.Trim() == string.Empty)
{
break;
}
}
}
}
}
}
public bool Confirm(string description)
{
if (IsNonInteractive)
{
return true;
}
var currentColor = ConsoleColor.Gray;
try
{
currentColor = System.Console.ForegroundColor;
System.Console.ForegroundColor = ConsoleColor.Yellow;
System.Console.Write(String.Format(CultureInfo.CurrentCulture, LocalizedResourceManager.GetString("ConsoleConfirmMessage"), description));
var result = System.Console.ReadLine();
return result.StartsWith(LocalizedResourceManager.GetString("ConsoleConfirmMessageAccept"), StringComparison.OrdinalIgnoreCase);
}
finally
{
System.Console.ForegroundColor = currentColor;
}
}
public ConsoleKeyInfo ReadKey()
{
EnsureInteractive();
return System.Console.ReadKey(intercept: true);
}
public string ReadLine()
{
EnsureInteractive();
return System.Console.ReadLine();
}
public void ReadSecureString(SecureString secureString)
{
EnsureInteractive();
try
{
ReadSecureStringFromConsole(secureString);
}
catch (InvalidOperationException)
{
// This can happen when you redirect nuget.exe input, either from the shell with "<" or
// from code with ProcessStartInfo.
// In this case, just read data from Console.ReadLine()
foreach (var c in ReadLine())
{
secureString.AppendChar(c);
}
}
secureString.MakeReadOnly();
}
private static void ReadSecureStringFromConsole(SecureString secureString)
{
// When you redirect nuget.exe input, either from the shell with "<" or
// from code with ProcessStartInfo, throw exception on mono.
if (!RuntimeEnvironmentHelper.IsWindows && RuntimeEnvironmentHelper.IsMono && _isatty(1) != 1)
{
throw new InvalidOperationException();
}
ConsoleKeyInfo keyInfo;
while ((keyInfo = System.Console.ReadKey(intercept: true)).Key != ConsoleKey.Enter)
{
if (keyInfo.Key == ConsoleKey.Backspace)
{
if (secureString.Length < 1)
{
continue;
}
System.Console.SetCursorPosition(System.Console.CursorLeft - 1, System.Console.CursorTop);
System.Console.Write(' ');
System.Console.SetCursorPosition(System.Console.CursorLeft - 1, System.Console.CursorTop);
secureString.RemoveAt(secureString.Length - 1);
}
else
{
secureString.AppendChar(keyInfo.KeyChar);
System.Console.Write('*');
}
}
System.Console.WriteLine();
}
private void EnsureInteractive()
{
if (IsNonInteractive)
{
throw new InvalidOperationException(LocalizedResourceManager.GetString("Error_CannotPromptForInput"));
}
}
public override void Log(ILogMessage message)
{
if (DisplayMessage(message.Level))
{
if (message.Level == LogLevel.Debug)
{
WriteColor(Out, ConsoleColor.Gray, message.Message);
}
else if (message.Level == LogLevel.Warning)
{
WriteWarning(message.FormatWithCode());
}
else if (message.Level == LogLevel.Error)
{
// Use standard error format for Packaging Errors
if (message.Code >= NuGetLogCode.NU5000 && message.Code <= NuGetLogCode.NU5500)
{
WriteError(string.Concat(LocalizedResourceManager.GetString("Error"), " ", message.FormatWithCode()));
}
else
{
WriteError(message.FormatWithCode());
}
}
else
{
// Verbose, Information
WriteLine(message.Message);
}
}
}
public override Task LogAsync(ILogMessage message)
{
Log(message);
return Task.CompletedTask;
}
private static LogLevel GetVerbosityLevel(Verbosity level)
{
switch (level)
{
case Verbosity.Detailed:
return LogLevel.Debug;
case Verbosity.Normal:
return LogLevel.Information;
case Verbosity.Quiet:
return LogLevel.Warning;
}
return LogLevel.Information;
}
}
}