mirror of https://github.com/dotnet/tye.git
committed by
GitHub
10 changed files with 263 additions and 10 deletions
@ -0,0 +1,55 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Microsoft.Tye.Hosting.Ansi2Html |
|||
{ |
|||
public static class Constants |
|||
{ |
|||
public const string Red = "#800000"; |
|||
public const string Black = "#000000"; |
|||
public const string Green = "#008000"; |
|||
public const string Yellow = "#808000"; |
|||
public const string Blue = "#000080"; |
|||
public const string Purple = "#800080"; |
|||
public const string Cyan = "#008080"; |
|||
public const string LightGray = "#c0c0c0"; |
|||
public const string DarkGray = "#808080"; |
|||
public const string BrightRed = "#ff0000"; |
|||
public const string BrightGreen = "#00ff00"; |
|||
public const string BrightYellow = "#ffff00"; |
|||
public const string BrightBlue = "#0000ff"; |
|||
public const string BrightPurple = "#ff00ff"; |
|||
public const string BrightCyan = "#00ffff"; |
|||
public const string White = "#ffffff"; |
|||
|
|||
public static Dictionary<string, string> ColorMap = new Dictionary<string, string>() |
|||
{ |
|||
{ "0", Black }, // Black
|
|||
{ "1", Red }, // Red
|
|||
{ "2", Green }, // Green
|
|||
{ "3", Yellow }, // Yellow
|
|||
{ "4", Blue }, // Blue
|
|||
{ "5", Purple }, // Purple
|
|||
{ "6", Cyan }, // Cyan
|
|||
{ "7", LightGray }, // Light Gray
|
|||
{ "8", DarkGray }, // Dark Gray
|
|||
{ "9", BrightRed }, // Bright Red
|
|||
{ "10", BrightGreen }, // Bright Green
|
|||
{ "11", BrightYellow }, // Bright Yellow
|
|||
{ "12", BrightBlue }, // Bright Blue
|
|||
{ "13", BrightPurple }, // Bright Purple
|
|||
{ "14", BrightCyan }, // Bright Cyan
|
|||
{ "15", White } // White
|
|||
}; |
|||
|
|||
public static class SelectGraphicRenditionParameters |
|||
{ |
|||
public const int Reset = 0; |
|||
|
|||
public static HashSet<int> SetForeground = new HashSet<int>() |
|||
{ |
|||
30, 31, 32, 33, 34, 35, 36, 37,38 |
|||
}; |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
|
|||
namespace Microsoft.Tye.Hosting.Ansi2Html |
|||
{ |
|||
public class Converter |
|||
{ |
|||
private readonly Regex _rule = new Regex("\u001b\\[(?<code>\\d+)(?<args>;\\d+)*m", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase); |
|||
|
|||
public string Parse(string input) |
|||
{ |
|||
var htmlText = _rule.Replace(input, match => |
|||
{ |
|||
var code = Convert.ToInt32(match.Groups["code"].Value); |
|||
var args = match.Groups["args"].Value; |
|||
List<string> attributes = args.Split(';').ToList(); |
|||
|
|||
var tagBuilder = new StringBuilder(); |
|||
if (code == Constants.SelectGraphicRenditionParameters.Reset) |
|||
{ |
|||
tagBuilder.Append("</span>"); |
|||
} |
|||
else |
|||
{ |
|||
var color = Constants.White; |
|||
if (attributes.Count > 0) |
|||
{ |
|||
string colorCode = attributes.Last(); |
|||
if (Constants.ColorMap.ContainsKey(colorCode)) |
|||
{ |
|||
color = Constants.ColorMap[colorCode]; |
|||
} |
|||
} |
|||
|
|||
tagBuilder.Append("<span style=\"color:"); |
|||
tagBuilder.Append(color); |
|||
tagBuilder.Append(";\">"); |
|||
} |
|||
|
|||
return tagBuilder.ToString(); |
|||
}); |
|||
|
|||
return htmlText; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using Microsoft.Tye.Hosting.Ansi2Html; |
|||
using Xunit; |
|||
|
|||
namespace Microsoft.Tye.UnitTests; |
|||
|
|||
public class Ansi2HtmlConverterTests |
|||
{ |
|||
[Theory] |
|||
[InlineData("\u001b[31;1mThis text is red\u001b[0m", $"<span style=\"color:{Constants.Red};\">This text is red</span>")] |
|||
[InlineData( |
|||
"\u001b[31;1m\u001b[0m\u001b[36;1m\u001b[36;1m 3 | \u001b[0m \u001b[36;1muvicorn\u001b[0m app.main:app --port $Env:PORT --reload --log-level debug\u001b[0m", |
|||
$"<span style=\"color:{Constants.Red};\"></span><span style=\"color:{Constants.Red};\"><span style=\"color:{Constants.Red};\"> 3 | </span> <span style=\"color:{Constants.Red};\">uvicorn</span> app.main:app --port $Env:PORT --reload --log-level debug</span>")] |
|||
public void ShouldParse(string input, string expected) |
|||
{ |
|||
Converter converter = new Converter(); |
|||
|
|||
string actual = converter.Parse(input); |
|||
|
|||
Assert.Equal(expected, actual); |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
using System.Collections.Generic; |
|||
using Microsoft.Tye.Hosting.Model; |
|||
using Xunit; |
|||
|
|||
namespace Microsoft.Tye.UnitTests |
|||
{ |
|||
public class ServiceUnitTests |
|||
{ |
|||
[Theory] |
|||
[MemberData(nameof(ServiceStateTestData))] |
|||
public void ServiceStateIsBasedOnReplicaStates(ServiceState expected, List<ReplicaState> replicaStates) |
|||
{ |
|||
Service service = new(new ServiceDescription("test", null), ServiceSource.Unknown); |
|||
|
|||
for (int i = 0; i < replicaStates.Count; i++) |
|||
{ |
|||
string replicaName = i.ToString(); |
|||
|
|||
service.Replicas.TryAdd(replicaName, new ReplicaStatus(service, replicaName) |
|||
{ |
|||
State = replicaStates[i], |
|||
}); |
|||
} |
|||
|
|||
Assert.Equal(expected, service.State); |
|||
|
|||
} |
|||
|
|||
public static IEnumerable<object[]> ServiceStateTestData => |
|||
new List<object[]> |
|||
{ |
|||
//no replica - should not happen
|
|||
new object[] { ServiceState.Unknown, new List<ReplicaState>() }, |
|||
|
|||
//one replica
|
|||
new object[] { ServiceState.Starting, new List<ReplicaState>() { ReplicaState.Added } }, |
|||
new object[] { ServiceState.Started, new List<ReplicaState>() { ReplicaState.Started } }, |
|||
new object[] { ServiceState.Started, new List<ReplicaState>() { ReplicaState.Ready } }, |
|||
new object[] { ServiceState.Started, new List<ReplicaState>() { ReplicaState.Healthy } }, |
|||
new object[] { ServiceState.Failed, new List<ReplicaState>() { ReplicaState.Removed } }, |
|||
new object[] { ServiceState.Stopped, new List<ReplicaState>() { ReplicaState.Stopped } }, |
|||
|
|||
//multiple replicas
|
|||
new object[] { ServiceState.Starting, new List<ReplicaState>() { ReplicaState.Added, ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, |
|||
new object[] { ServiceState.Started, new List<ReplicaState>() { ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, |
|||
new object[] { ServiceState.Degraded, new List<ReplicaState>() { ReplicaState.Removed, ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, |
|||
new object[] { ServiceState.Degraded, new List<ReplicaState>() { ReplicaState.Stopped, ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, |
|||
new object[] { ServiceState.Degraded, new List<ReplicaState>() { ReplicaState.Removed, ReplicaState.Stopped, ReplicaState.Started, ReplicaState.Ready, ReplicaState.Healthy } }, |
|||
new object[] { ServiceState.Stopped, new List<ReplicaState>() { ReplicaState.Stopped, ReplicaState.Stopped, ReplicaState.Stopped } }, |
|||
}; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue