Typed tree to retrieve configuration tree
This commit is contained in:
parent
96cb8df66f
commit
36b776d6d1
|
@ -1,4 +1,5 @@
|
|||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Sharp.Augeas.Test;
|
||||
|
||||
|
@ -29,11 +30,10 @@ public class AugeasTests
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void NoExceptionThrownWhenPrintingVirtualhostTree()
|
||||
public void GetTreeHasDirectivesAndArguments()
|
||||
{
|
||||
var virtualHostConfig = EXAMPLE_CONF_1;
|
||||
_augeas.PrintVirtualHostTree(virtualHostConfig);
|
||||
Assert.Pass();
|
||||
var tree = _augeas.GetTree("VirtualHost", $"/files{EXAMPLE_CONF_1}/VirtualHost/*");
|
||||
Assert.That(tree.Arguments.Count > 0 && tree.Directives.Count > 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -75,6 +75,7 @@ public class AugeasTests
|
|||
{
|
||||
Assert.Fail("Unable to write changes to disk.");
|
||||
}
|
||||
|
||||
var retrieveVal = _augeas.GetNode(nodePath);
|
||||
Assert.That(retrieveVal == newValue);
|
||||
}
|
||||
|
@ -99,7 +100,6 @@ public class AugeasTests
|
|||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void MatchCanReturnMultipleDirectives()
|
||||
{
|
||||
|
@ -108,13 +108,4 @@ public class AugeasTests
|
|||
Assert.That(sites.Length > 0);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void GetTreeVirtualHostReturnsDictionaryWithKeys()
|
||||
{
|
||||
var path = EXAMPLE_CONF_1;
|
||||
var tree = _augeas.GetVirtualHostTree(path);
|
||||
Assert.That(tree.Count > 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using System.Runtime.InteropServices;using Sharp.Augeas.Test;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Sharp.Augeas.Test;
|
||||
using static Sharp.Augeas.AugeasExtern;
|
||||
|
||||
namespace Sharp.Augeas
|
||||
|
@ -8,12 +10,13 @@ namespace Sharp.Augeas
|
|||
/// </summary>
|
||||
public sealed unsafe class Augeas
|
||||
{
|
||||
|
||||
#region Flags
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static int NONE = 0;
|
||||
|
||||
public static int SAVE_BACKUP = (1 << 0);
|
||||
public static int SAVE_NEWFILE = (1 << 1);
|
||||
public static int TYPE_CHECK = (1 << 2);
|
||||
|
@ -23,22 +26,23 @@ namespace Sharp.Augeas
|
|||
|
||||
public static int NO_MODL_AUTOLOAD = (1 << 6);
|
||||
public static int AUG_ENABLE_SPAN = (1 << 7);
|
||||
|
||||
#endregion Flags
|
||||
|
||||
|
||||
private readonly IntPtr _augeas;
|
||||
|
||||
private HashSet<string> _loadedFiles = new();
|
||||
|
||||
#region Constructor / Destructor
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Augeas Core Destructor
|
||||
/// </summary>
|
||||
~Augeas()
|
||||
{
|
||||
{
|
||||
close_aug(_augeas);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Augeas Core constructor
|
||||
/// </summary>
|
||||
|
@ -60,7 +64,7 @@ namespace Sharp.Augeas
|
|||
public Augeas(string root)
|
||||
{
|
||||
var lensPath = Environment.GetEnvironmentVariable("AUG_LENS_PATH");
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(lensPath))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
|
@ -68,21 +72,19 @@ namespace Sharp.Augeas
|
|||
}
|
||||
|
||||
var augSettings = new AugSettings(root, lensPath);
|
||||
|
||||
|
||||
_augeas = init_aug(augSettings, NO_STDINC | NO_LOAD);
|
||||
|
||||
|
||||
if (_augeas == IntPtr.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("Augeas is not a valid instance.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Augeas Internal Api
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Prints a preview of the desired segment in <see cref="matchPath"/>
|
||||
/// </summary>
|
||||
|
@ -114,7 +116,7 @@ namespace Sharp.Augeas
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool success = load_file(_augeas, configurationFilePath);
|
||||
|
||||
_loadedFiles.Add(configurationFilePath);
|
||||
|
@ -145,9 +147,9 @@ namespace Sharp.Augeas
|
|||
/// </summary>
|
||||
/// <param name="matchPath">Configuration path.</param>
|
||||
/// <returns>Dictionary with the Tree</returns>
|
||||
private Dictionary<string,string> GetTree(string matchPath)
|
||||
public Dictionary<string, string> GetDictionaryTree(string matchPath)
|
||||
{
|
||||
var result = new Dictionary<string, string>();
|
||||
var result = new Dictionary<string, string>();
|
||||
var raw = get_tree(_augeas, matchPath);
|
||||
string sb = Marshal.PtrToStringAnsi(raw);
|
||||
var lines = sb.Split(";ENDL;");
|
||||
|
@ -159,6 +161,7 @@ namespace Sharp.Augeas
|
|||
result.Add(pair[0].Remove(0, 3), pair[1]);
|
||||
}
|
||||
}
|
||||
|
||||
FreeString(raw);
|
||||
return result;
|
||||
}
|
||||
|
@ -188,7 +191,7 @@ namespace Sharp.Augeas
|
|||
|
||||
public int InsertNode(string matchPath, string label, int before = 0)
|
||||
{
|
||||
return insert_node(_augeas, matchPath, label, before);
|
||||
return insert_node(_augeas, matchPath, label, before);
|
||||
}
|
||||
|
||||
|
||||
|
@ -219,16 +222,16 @@ namespace Sharp.Augeas
|
|||
FreeString(raw);
|
||||
return sb;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Matches of the path expression PATH in AUG.
|
||||
/// </summary>
|
||||
/// <param name="matchPath">Augeas path.</param>
|
||||
/// <returns></returns>
|
||||
public string[] Match (string matchPath)
|
||||
public string[] Match(string matchPath)
|
||||
{
|
||||
sbyte** result = null;
|
||||
var count = match(_augeas, matchPath, &result);
|
||||
|
@ -248,42 +251,9 @@ namespace Sharp.Augeas
|
|||
result[i] = Marshal.PtrToStringUTF8((IntPtr)list[i]);
|
||||
Marshal.FreeCoTaskMem((IntPtr)list[i]);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Given a <see cref="apacheSitePath"/>, prints the Virtual Host tree.
|
||||
/// </summary>
|
||||
/// <param name="apacheSitePath">Apache configuration file.</param>
|
||||
public void PrintVirtualHostTree(string apacheSitePath)
|
||||
{
|
||||
LoadFile(apacheSitePath);
|
||||
string virtualHostTree = $"/files{apacheSitePath}/VirtualHost/*";
|
||||
PrintTree(virtualHostTree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a <see cref="apacheSitePath"/>, gets a virtual host tree.
|
||||
/// </summary>
|
||||
/// <param name="apacheSitePath">Apache configuration file.</param>
|
||||
/// <returns></returns>
|
||||
public Dictionary<string,string> GetVirtualHostTree(string apacheSitePath)
|
||||
{
|
||||
LoadFile(apacheSitePath);
|
||||
string virtualHostTree = $"/files{apacheSitePath}/VirtualHost/*";
|
||||
return GetTree(virtualHostTree);
|
||||
}
|
||||
|
||||
void PrintVirtualHostProxyTree(string apacheSitePath)
|
||||
{
|
||||
LoadFile(apacheSitePath);
|
||||
string virtualHostProxyMatchPath = $"/files{apacheSitePath}/VirtualHost/Proxy/*";
|
||||
PrintTree(virtualHostProxyMatchPath);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -15,7 +15,7 @@
|
|||
<TargetPath>root\%(RecursiveDir)\%(Filename)%(Extension)</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</ItemGroup>
|
||||
<ItemGroup >
|
||||
<ItemGroup>
|
||||
<Content Include="./Platform/Linux/libclAugeas.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
namespace Sharp.Augeas;
|
||||
|
||||
public class Argument : Node
|
||||
{
|
||||
|
||||
public string Value;
|
||||
|
||||
public bool SetValue(string newValue)
|
||||
{
|
||||
Value = newValue;
|
||||
return _augeas.SetNode(Path, newValue);
|
||||
}
|
||||
|
||||
public Argument(Augeas augeas, string id, string path, string value) : base(augeas, path)
|
||||
{
|
||||
Id = id;
|
||||
Path = path;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
using System.Text;
|
||||
|
||||
namespace Sharp.Augeas;
|
||||
|
||||
public class Directive : Node
|
||||
{
|
||||
public string Value;
|
||||
public List<Argument> Arguments;
|
||||
public bool HasArguments => Arguments.Count != 0;
|
||||
|
||||
/// <summary>
|
||||
/// Sets a new value for the directive using string literals
|
||||
/// The values are separated by spaces, the first value is the directive value,
|
||||
/// the other values are values corresponding to the arguments.
|
||||
/// </summary>
|
||||
/// <param name="newValue"></param>
|
||||
public void Set(string newValue)
|
||||
{
|
||||
var splitted = newValue.Split(" ");
|
||||
|
||||
if (splitted.Length > 0)
|
||||
{
|
||||
SetValue(splitted[0]);
|
||||
}
|
||||
|
||||
for (int i = 1; i < splitted.Length; i++)
|
||||
{
|
||||
var argumentIndex = i - 1;
|
||||
Arguments[argumentIndex].SetValue(splitted[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the value of this directive.
|
||||
/// Note: This doesn't write any changes to disk.
|
||||
/// </summary>
|
||||
/// <param name="newValue">New value.</param>
|
||||
/// <returns></returns>
|
||||
public bool SetValue(string newValue)
|
||||
{
|
||||
Value = newValue;
|
||||
return _augeas.SetNode(Path, newValue);
|
||||
}
|
||||
|
||||
public Directive(Augeas augeas, string id, string path, string value) : base(augeas, path)
|
||||
{
|
||||
Value = value;
|
||||
Id = id;
|
||||
Path = path;
|
||||
Arguments = new List<Argument>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a argument to this node.
|
||||
/// </summary>
|
||||
/// <param name="argument"></param>
|
||||
public void AddArgument(Argument argument)
|
||||
{
|
||||
argument.Parent = this;
|
||||
Arguments.Add(argument);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder($"{Value} ");
|
||||
|
||||
foreach (var arg in Arguments)
|
||||
{
|
||||
sb.Append($"{arg} ");
|
||||
}
|
||||
|
||||
return sb.ToString().TrimEnd();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
namespace Sharp.Augeas;
|
||||
|
||||
public class Node
|
||||
{
|
||||
public string Id;
|
||||
public Node Parent;
|
||||
public string Path;
|
||||
protected readonly Augeas _augeas;
|
||||
|
||||
public Node(Augeas augeas, string path)
|
||||
{
|
||||
_augeas = augeas;
|
||||
Parent = null;
|
||||
Path = path;
|
||||
}
|
||||
public Node(Augeas augeas, Node parent, string path)
|
||||
{
|
||||
_augeas = augeas;
|
||||
Parent = parent;
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public bool Save()
|
||||
{
|
||||
return _augeas.Save();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System.Text;
|
||||
|
||||
namespace Sharp.Augeas
|
||||
{
|
||||
public class SuperNode : Node
|
||||
{
|
||||
public List<Directive> Directives;
|
||||
public List<Argument> Arguments;
|
||||
public List<SuperNode> SuperNodes;
|
||||
|
||||
public SuperNode(Augeas augeas, string path, string id) : base(augeas, path)
|
||||
{
|
||||
Path = path;
|
||||
Id = id;
|
||||
Directives = new List<Directive>();
|
||||
Arguments = new List<Argument>();
|
||||
SuperNodes = new List<SuperNode>();
|
||||
}
|
||||
|
||||
public Directive GetDirective(string value)
|
||||
{
|
||||
return Directives.FirstOrDefault(d => d.Value == value, null);
|
||||
}
|
||||
|
||||
public void AddArgument(Argument argument)
|
||||
{
|
||||
argument.Parent = this;
|
||||
Arguments.Add(argument);
|
||||
}
|
||||
|
||||
public void AddDirective(Directive directive)
|
||||
{
|
||||
directive.Parent = this;
|
||||
Directives.Add(directive);
|
||||
}
|
||||
|
||||
public void AddSuperNode(SuperNode superNode)
|
||||
{
|
||||
superNode.Parent = this;
|
||||
SuperNodes.Add(superNode);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder($"{Id} ");
|
||||
|
||||
foreach (var arg in Arguments)
|
||||
{
|
||||
sb.Append($"{arg} ");
|
||||
}
|
||||
|
||||
return sb.ToString().TrimEnd();;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
using System.Text;
|
||||
|
||||
namespace Sharp.Augeas;
|
||||
|
||||
public static class TreeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds a typed tree with the <see cref="augeasPath"/>
|
||||
/// </summary>
|
||||
/// <param name="augeas"></param>
|
||||
/// <param name="superNodeName">Super node name.</param>
|
||||
/// <param name="augeasPath">Augeas path.</param>
|
||||
/// <returns></returns>
|
||||
public static SuperNode GetTree(this Augeas augeas, string superNodeName, string augeasPath)
|
||||
{
|
||||
var basePath = augeasPath.Replace("*", "");
|
||||
var tree = augeas.GetDictionaryTree(augeasPath);
|
||||
Dictionary<string, Directive> addedDirectives = new Dictionary<string, Directive>();
|
||||
Dictionary<string, SuperNode> addedSuperNodes = new Dictionary<string, SuperNode>();
|
||||
addedSuperNodes.Add(superNodeName, new SuperNode(augeas, augeasPath, superNodeName));
|
||||
|
||||
foreach (var treeKey in tree.Keys)
|
||||
{
|
||||
var hierarchy = treeKey.Split('/');
|
||||
var firstElement = hierarchy[0];
|
||||
// Parent
|
||||
if (hierarchy.Length <= 1)
|
||||
{
|
||||
var rFullPath = $"{basePath}{firstElement}";
|
||||
if (firstElement.StartsWith("directive"))
|
||||
{
|
||||
Directive directive = new Directive(augeas, firstElement, rFullPath, tree[firstElement]);
|
||||
directive.Parent = addedSuperNodes[superNodeName];
|
||||
addedSuperNodes[superNodeName].AddDirective(directive);
|
||||
addedDirectives.Add(treeKey, directive);
|
||||
continue;
|
||||
}
|
||||
// If is argument
|
||||
if (firstElement.StartsWith("arg"))
|
||||
{
|
||||
Argument argument = new Argument(augeas, firstElement, rFullPath, tree[firstElement]);
|
||||
argument.Parent = addedSuperNodes[superNodeName];
|
||||
addedSuperNodes[superNodeName].AddArgument(argument);
|
||||
continue;
|
||||
}
|
||||
if (IsSuperNodeCandidate(firstElement) && !addedSuperNodes.ContainsKey(firstElement))
|
||||
{
|
||||
var superNode = new SuperNode(augeas, rFullPath, firstElement);
|
||||
superNode.Parent = addedSuperNodes[superNodeName];
|
||||
addedSuperNodes.Add(firstElement, superNode);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// handle children
|
||||
for (var i = 1; i < hierarchy.Length; i++)
|
||||
{
|
||||
var childKey = hierarchy[i];
|
||||
var parentPathBuilder = new StringBuilder();
|
||||
|
||||
for (int j = 0; j < i; j++) parentPathBuilder.Append($"{hierarchy[j]}/");
|
||||
|
||||
var parentPath = parentPathBuilder.ToString();
|
||||
parentPath = parentPath.Trim('/');
|
||||
var fullPath = $"{parentPath}/{childKey}";
|
||||
var rFullPath = $"{basePath}{fullPath}";
|
||||
var childValue = tree[fullPath];
|
||||
|
||||
if (IsSuperNodeCandidate(firstElement) && !addedSuperNodes.ContainsKey(firstElement))
|
||||
{
|
||||
var superNode = new SuperNode(augeas, rFullPath, firstElement);
|
||||
superNode.Parent = addedSuperNodes[superNodeName];
|
||||
addedSuperNodes.Add(firstElement, superNode);
|
||||
}
|
||||
if (childKey.StartsWith("directive"))
|
||||
{
|
||||
Directive directive = new Directive(augeas, childKey, rFullPath, childValue);
|
||||
if (addedDirectives.ContainsKey(fullPath)) continue;
|
||||
addedDirectives.Add(fullPath, directive);
|
||||
if (addedSuperNodes.ContainsKey(parentPath))
|
||||
addedSuperNodes[parentPath].AddDirective(directive);
|
||||
|
||||
continue;
|
||||
}
|
||||
if (childKey.StartsWith("arg"))
|
||||
{
|
||||
Argument argument = new Argument(augeas, childKey, rFullPath, childValue);
|
||||
|
||||
if (addedDirectives.ContainsKey(parentPath))
|
||||
{
|
||||
addedDirectives[parentPath].AddArgument(argument);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addedSuperNodes.ContainsKey(parentPath))
|
||||
addedSuperNodes[parentPath].AddArgument(argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var superNodes = addedSuperNodes.Keys;
|
||||
|
||||
foreach (var key in superNodes)
|
||||
{
|
||||
if (key != superNodeName)
|
||||
{
|
||||
addedSuperNodes[superNodeName].AddSuperNode(addedSuperNodes[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return addedSuperNodes[superNodeName];
|
||||
}
|
||||
|
||||
|
||||
private static bool IsSuperNodeCandidate(string key)
|
||||
{
|
||||
return !key.StartsWith("arg") && !key.StartsWith("directive");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace Sharp.Augeas;
|
||||
|
||||
public static class ApacheConfigExtensions
|
||||
{
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
namespace Sharp.Augeas;
|
||||
|
||||
public class Argument<T> : Node where T: Node
|
||||
{
|
||||
public new T Parent;
|
||||
|
||||
public string Value;
|
||||
|
||||
public Argument(T parent, string value)
|
||||
{
|
||||
Parent = parent;
|
||||
Children = null;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public Argument()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Sharp.Augeas;
|
||||
|
||||
public class Directive : Node
|
||||
{
|
||||
public string Value;
|
||||
public List<Argument> Arguments;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
namespace Sharp.Augeas;
|
||||
|
||||
public class Node
|
||||
{
|
||||
public Node Parent;
|
||||
public List<Node> Children;
|
||||
|
||||
|
||||
public Node()
|
||||
{
|
||||
Parent = null;
|
||||
Children = new List<Node>();
|
||||
}
|
||||
public Node(Node parent)
|
||||
{
|
||||
Parent = parent;
|
||||
Children = new List<Node>();
|
||||
}
|
||||
|
||||
public T[] GetChildren<T>()
|
||||
{
|
||||
return Children
|
||||
.OfType<T>()
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public Node(Node parent, List<Node> children)
|
||||
{
|
||||
Parent = parent;
|
||||
Children = children;
|
||||
}
|
||||
|
||||
public void AddChild(Node node)
|
||||
{
|
||||
Children.Add(node);
|
||||
}
|
||||
|
||||
public void RemoveChild(Node child)
|
||||
{
|
||||
if (Children.Contains(child))
|
||||
{
|
||||
Children.Remove(child);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAllChildren()
|
||||
{
|
||||
Children = new List<Node>();
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Sharp.Augeas;
|
||||
|
||||
public class Proxy : Node
|
||||
{
|
||||
public new VirtualHost Parent;
|
||||
public List<Directive<Proxy>> Directives;
|
||||
public List<Argument<Proxy>> Arguments;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace Sharp.Augeas
|
||||
{
|
||||
public class VirtualHost : Node
|
||||
{
|
||||
public List<Directive<Proxy>> Directives;
|
||||
public List<Argument<Proxy>> Arguments;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
namespace Sharp.Augeas;
|
||||
|
||||
public static class VirtualHostTreeGenerator
|
||||
{
|
||||
public static VirtualHost Generate(Dictionary<string,string> dic)
|
||||
{
|
||||
var keys = dic.Keys;
|
||||
var virtualHost = new VirtualHost();
|
||||
foreach (var key in keys)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return virtualHost;
|
||||
}
|
||||
|
||||
private static bool IsProxy(string key)
|
||||
{
|
||||
return key.Contains("f/VirtualHost/Proxy/");
|
||||
}
|
||||
private static bool IsVirtualHostArg(string key)
|
||||
{
|
||||
return key.Contains("f/VirtualHost/arg;");
|
||||
}
|
||||
private static bool IsProxyDirective(string key)
|
||||
{
|
||||
return key.Contains("f/VirtualHost/Proxy/directive");
|
||||
}
|
||||
private static bool IsVirtualHostDirective(string key)
|
||||
{
|
||||
return key.Contains("f/VirtualHost/directive");
|
||||
}
|
||||
private static bool IsDirectiveArg(string key)
|
||||
{
|
||||
return key.Contains("f/VirtualHost/directive");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue