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

- Improve console prompt default handling #206

Merged
merged 1 commit into from
Mar 22, 2024
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
16 changes: 8 additions & 8 deletions src/Nox.Cli.Abstractions/Helpers/YamlHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Nox.Cli.Abstractions.Helpers;

public static class YamlHelper
{
private static readonly Regex _referenceRegex = new(@"\$ref\S*:\s*(?<variable>[\w:\.\/\\]+\b[\w\-\.\/]+)\s*", RegexOptions.Compiled | RegexOptions.IgnoreCase, TimeSpan.FromSeconds(5));
private static readonly Regex _referenceRegex = new(@"(?<!\x22)(\$ref\S*:\s*(?<variable>[\w:\.\/\\]+\b[\w\-\.\/]+)\s*)", RegexOptions.Compiled | RegexOptions.IgnoreCase, TimeSpan.FromSeconds(5));

/// <summary>
/// Resolve $ref &lt;path&gt; tags in a yaml source yaml file. <br/>
Expand All @@ -22,7 +22,7 @@ public static string ResolveYamlReferences(string path)
var sourcePath = Path.GetDirectoryName(sourceFullPath);

var sourceLines = File.ReadAllLines(path);
var outputLines = ResolveYamlReferences(sourceLines.ToList(), sourcePath!).Result;
var outputLines = ResolveYamlReferences(sourceLines.ToList(), sourcePath!, Path.GetFileName(path)).Result;

return string.Join('\n', outputLines.ToArray());
}
Expand All @@ -42,12 +42,12 @@ public static async Task<string> ResolveYamlReferencesAsync(string path)
var sourcePath = Path.GetDirectoryName(sourceFullPath);

var sourceLines = await File.ReadAllLinesAsync(path);
var outputLines = await ResolveYamlReferences(sourceLines.ToList(), sourcePath!);
var outputLines = await ResolveYamlReferences(sourceLines.ToList(), sourcePath!, Path.GetFileName(path));

return string.Join('\n', outputLines.ToArray());
}

private static async Task<List<string>> ResolveYamlReferences(List<string> sourceLines, string path)
private static async Task<List<string>> ResolveYamlReferences(List<string> sourceLines, string path, string parentFile)
{
var outputLines = new List<string>();
foreach (var sourceLine in sourceLines)
Expand All @@ -58,9 +58,9 @@ private static async Task<List<string>> ResolveYamlReferences(List<string> sourc
if (match.Success)
{
var padding = new string(' ', match.Index);
var childPath = match.Groups[1].Value;
var childPath = match.Groups[^1].Value;
if (!Path.IsPathRooted(childPath)) childPath = Path.Combine(path!, childPath);
if (!File.Exists(childPath)) throw new NoxCliException($"Referenced yaml file does not exist for reference: {match.Groups[1].Value}");
if (!File.Exists(childPath)) throw new NoxCliException($"Referenced yaml file does not exist for reference: {match.Groups[1].Value} in file: {parentFile}");
var childLines = await File.ReadAllLinesAsync(childPath);
foreach (var childLine in childLines)
{
Expand All @@ -78,9 +78,9 @@ private static async Task<List<string>> ResolveYamlReferences(List<string> sourc
}
}

if (outputLines.Any(ol => ol.Contains("$ref:") && !ol.TrimStart().StartsWith('#')))
if (outputLines.Any(ol => ol.Contains("$ref:") && !ol.Contains("\"$ref:") && !ol.TrimStart().StartsWith('#')))
{
outputLines = await ResolveYamlReferences(outputLines, path);
outputLines = await ResolveYamlReferences(outputLines, path, parentFile);
}

return outputLines;
Expand Down
4 changes: 2 additions & 2 deletions src/Nox.Cli.Caching/NoxCliCacheBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ public class NoxCliCacheBuilder
{
private readonly NoxCliCacheManager _manager;

public NoxCliCacheBuilder(string remoteUrl, IPersistedTokenCache? tokenCache = null)
public NoxCliCacheBuilder(string remoteUrl, bool forceOffline, IPersistedTokenCache? tokenCache = null)
{
_manager = new NoxCliCacheManager(remoteUrl, tokenCache);
_manager = new NoxCliCacheManager(remoteUrl, forceOffline, tokenCache);
}

public NoxCliCacheBuilder ForServer()
Expand Down
58 changes: 30 additions & 28 deletions src/Nox.Cli.Caching/NoxCliCacheManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class NoxCliCacheManager: INoxCliCacheManager
private string _workflowCachePath;
private string _templateCachePath;
private string _localWorkflowPath;
private bool _forceOffline;
private bool _isServer;
private readonly Uri _remoteUri;
private Uri? _workflowUri;
Expand All @@ -37,6 +38,29 @@ public class NoxCliCacheManager: INoxCliCacheManager
private IDeserializer _deserializer;
private string? _tenantId;

public NoxCliCacheManager(string? remoteUrl, bool forceOffline, IPersistedTokenCache? tokenCache = null)
{
_buildLog = new List<string>();
if (string.IsNullOrEmpty(remoteUrl))
{
_remoteUri = new Uri("https://noxorg.dev");
}
else
{
_remoteUri = new Uri(remoteUrl);
}

_forceOffline = forceOffline;
_cachePath = WellKnownPaths.CachePath;
_workflowCachePath = WellKnownPaths.WorkflowsCachePath;
_templateCachePath = WellKnownPaths.TemplatesCachePath;
Directory.CreateDirectory(_cachePath);
_cacheFile = WellKnownPaths.CacheFile;
_localWorkflowPath = ".";
_tokenCache = tokenCache;
_deserializer = BuildDeserializer();
}

internal void ForServer()
{
_isServer = true;
Expand Down Expand Up @@ -73,6 +97,7 @@ internal void AddBuildEventHandler(EventHandler<ICacheManagerBuildEventArgs> han
public bool IsOnline {
get
{
if (_forceOffline) return false;
if (_remoteUri.Host == "localhost") return true;
return PingHelper.ServicePing(_remoteUri.Host);
}
Expand Down Expand Up @@ -138,32 +163,6 @@ public void RefreshTemplate(string name)
}
}
}
else
{
throw new NoxCliException($"Unable to communicate with the online cache.");
}
}

public NoxCliCacheManager(string? remoteUrl, IPersistedTokenCache? tokenCache = null)
{
_buildLog = new List<string>();
if (string.IsNullOrEmpty(remoteUrl))
{
_remoteUri = new Uri("https://noxorg.dev");
}
else
{
_remoteUri = new Uri(remoteUrl);
}

_cachePath = WellKnownPaths.CachePath;
_workflowCachePath = WellKnownPaths.WorkflowsCachePath;
_templateCachePath = WellKnownPaths.TemplatesCachePath;
Directory.CreateDirectory(_cachePath);
_cacheFile = WellKnownPaths.CacheFile;
_localWorkflowPath = ".";
_tokenCache = tokenCache;
_deserializer = BuildDeserializer();
}

internal INoxCliCacheManager Build()
Expand Down Expand Up @@ -494,9 +493,12 @@ private string[] FindWorkflowsAndManifest(string searchPath = "")
private FileInfo[] GetFilesWithSearchPatterns(DirectoryInfo path, string[] searchPatterns, SearchOption searchOption)
{
var files = new List<FileInfo>();
foreach (var pattern in searchPatterns)
if (path.Exists)
{
files.AddRange( path.GetFiles(pattern, searchOption) );
foreach (var pattern in searchPatterns)
{
files.AddRange( path.GetFiles(pattern, searchOption) );
}
}
return files.ToArray();
}
Expand Down
6 changes: 3 additions & 3 deletions src/Nox.Cli.Helpers/YamlCleaner.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.CodeDom.Compiler;
using System.Text;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;
Expand All @@ -13,11 +14,10 @@ public static StringBuilder RemoveEmptyNodes(StringBuilder sourceYaml)
yaml.Load(input);
var root = (YamlMappingNode)yaml.Documents[0].RootNode;
RemoveEmptyChildren(root);
var yamlDoc = new YamlDocument(root);
var yamlStream = new YamlStream(yamlDoc);
var sb = new StringBuilder();
var writer = new StringWriter(sb);
yamlStream.Save(writer, false);
var textWriter = new IndentedTextWriter(writer, " ");
yaml.Save(textWriter, false);
writer.Flush();
writer.Close();
return sb;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ public NoxActionMetaData Discover()
private readonly RestClient _client = new();

private readonly Regex _resolveRefs = new("\"\\$ref\\\"\\s*:\\s*\\\"(?<url>[\\w:/\\.]+)\\\"", RegexOptions.Compiled | RegexOptions.IgnoreCase);

private readonly Regex _yamlVariableRegex = new(@"\$\{\{\s*(yaml)\.(?<variable>\b[\w\-_:]+)\s*\}\}", RegexOptions.Compiled | RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1));

private readonly Dictionary<string, object> _responses = new();

Expand Down Expand Up @@ -199,7 +201,7 @@ public async Task<IDictionary<string, object>> ProcessAsync(INoxWorkflowContext

if (_fileOptions != null && _fileOptions.ContainsKey("filename"))
{
_yaml = YamlCleaner.RemoveEmptyNodes(_yaml);
//_yaml = YamlCleaner.RemoveEmptyNodes(_yaml);

_yaml.Insert(0, Environment.NewLine);

Expand Down Expand Up @@ -297,6 +299,7 @@ private async Task ProcessSchema(JsonSchema.JsonSchema schema, string rootKey =
{
var newKey = $"{rootKey}.{key}".TrimStart('.');


var prefix = $"[grey]{newKey.PadRight(40, '.').EscapeMarkup()}[/] ";
var yamlSpacing = new string(' ', newKey.Count(d => d == '.') * 2);

Expand Down Expand Up @@ -547,42 +550,80 @@ private void AppendKey(string yamlSpacing, string key)
{
if (_defaults?.ContainsKey(key) ?? false)
{
return (T)Convert.ChangeType(_defaults[key], typeof(T));
var defaultValue = _defaults[key];
var match = _yamlVariableRegex.Match(defaultValue.ToString()!);
if (match.Success)
{
var variableValue = _responses[match.Groups["variable"].ToString()].ToString();
return (T)Convert.ChangeType(defaultValue.ToString()!.Replace(match.Groups[0].ToString(), variableValue), typeof(T));
}
else
{
return (T)Convert.ChangeType(defaultValue, typeof(T));
}
}

return default;
}

private void ProcessDefaults(string key, string yamlSpacing, string yamlSpacingPostfix)
{
Regex defaultArrayRegex = new(@"\[(.*?)\]\.(.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1));
var processor = new DefaultsProcessor();
foreach (var defaultEntry in _defaults!.Where(d => d.Key.StartsWith(key, StringComparison.CurrentCultureIgnoreCase)))
{
processor.Process(defaultEntry);
}

_yaml.AppendLine($"{yamlSpacing}{key}:");
var arrayIndex = -1;
foreach (var defaultItem in _defaults!.Where(d => d.Key.StartsWith(key, StringComparison.CurrentCultureIgnoreCase)))
AppendYaml(processor.Result!, yamlSpacing);
}

private void AppendYaml(DefaultNode node, string yamlSpacing, string spacingPostFix = "")
{
var value = "";
if (!string.IsNullOrWhiteSpace(node.Value)) value = node.Value;
var key = node.Key;
if (key.StartsWith('['))
{
//check if this item is an array
var itemKey = defaultItem.Key;
var defaultSpacing = new string(' ', itemKey.Count(d => d == '.') * 2);
var match = defaultArrayRegex.Match(itemKey);
if (match.Success) //array
if (node.Children is { Count: > 0 } || node.Value!.StartsWith("$ref"))
{
if (int.TryParse(match.Groups[1].ToString(), out var itemIndex))
{
var defaultPrefix = " ";
if (itemIndex != arrayIndex)
{
defaultPrefix = "- ";
arrayIndex = itemIndex;
}
_yaml.AppendLine($"{defaultSpacing}{defaultPrefix}{match.Groups[2]}: {defaultItem.Value}");
}
spacingPostFix = "- ";
}
else
{
_yaml.AppendLine($"{yamlSpacing}{yamlSpacingPostfix}{key}: {_defaults![key]}");
_yaml.AppendLine($"{yamlSpacing}{value}");
}
}
else
{
key += ": ";
yamlSpacing = AddPostFix(yamlSpacing, spacingPostFix);
_yaml.AppendLine($"{yamlSpacing}{key}{value}");
}

if (node.Children.Count != 0)
{
yamlSpacing += " ";
foreach (var childNode in node.Children)
{
AppendYaml(childNode, yamlSpacing, spacingPostFix);
spacingPostFix = "";
}
}
else if (node.Value!.StartsWith("$ref"))
{
yamlSpacing += " ";
yamlSpacing = AddPostFix(yamlSpacing, spacingPostFix);
_yaml.AppendLine($"{yamlSpacing}{value}");
}

}

private string AddPostFix(string source, string postFix)
{
if (string.IsNullOrEmpty(postFix)) return source;
var result = source.Substring(0, source.Length - postFix.Length);
result += postFix;
return result;
}
}

8 changes: 8 additions & 0 deletions src/Nox.Cli.Plugins/Nox.Cli.Plugin.Console/DefaultNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Nox.Cli.Plugin.Console;

public class DefaultNode
{
public string Key { get; set; } = string.Empty;
public string? Value { get; set; }
public List<DefaultNode> Children { get; set; } = new();
}
Loading
Loading