diff --git a/Sharp.Augeas.Test/AugeasTests.cs b/Sharp.Augeas.Test/AugeasTests.cs index 3a82049..be8776f 100644 --- a/Sharp.Augeas.Test/AugeasTests.cs +++ b/Sharp.Augeas.Test/AugeasTests.cs @@ -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); - } - } \ No newline at end of file diff --git a/Sharp.Augeas/Augeas/Augeas.cs b/Sharp.Augeas/Augeas/Augeas.cs index eb76c89..fe691ef 100644 --- a/Sharp.Augeas/Augeas/Augeas.cs +++ b/Sharp.Augeas/Augeas/Augeas.cs @@ -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 /// public sealed unsafe class Augeas { - #region Flags + /// /// /// 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 _loadedFiles = new(); #region Constructor / Destructor - + /// /// Augeas Core Destructor /// ~Augeas() - { + { close_aug(_augeas); } - + /// /// Augeas Core constructor /// @@ -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 - /// /// Prints a preview of the desired segment in /// @@ -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 /// /// Configuration path. /// Dictionary with the Tree - private Dictionary GetTree(string matchPath) + public Dictionary GetDictionaryTree(string matchPath) { - var result = new Dictionary(); + var result = new Dictionary(); 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 + + /// /// Matches of the path expression PATH in AUG. /// /// Augeas path. /// - 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; } - - - - /// - /// Given a , prints the Virtual Host tree. - /// - /// Apache configuration file. - public void PrintVirtualHostTree(string apacheSitePath) - { - LoadFile(apacheSitePath); - string virtualHostTree = $"/files{apacheSitePath}/VirtualHost/*"; - PrintTree(virtualHostTree); - } - - /// - /// Given a , gets a virtual host tree. - /// - /// Apache configuration file. - /// - public Dictionary 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); - } - } -} +} \ No newline at end of file diff --git a/Sharp.Augeas/Platform/Linux/libclAugeas.so b/Sharp.Augeas/Platform/Linux/libclAugeas.so index 6903728..e69de29 100644 Binary files a/Sharp.Augeas/Platform/Linux/libclAugeas.so and b/Sharp.Augeas/Platform/Linux/libclAugeas.so differ diff --git a/Sharp.Augeas/Sharp.Augeas.csproj b/Sharp.Augeas/Sharp.Augeas.csproj index ddd724c..56cc1ed 100644 --- a/Sharp.Augeas/Sharp.Augeas.csproj +++ b/Sharp.Augeas/Sharp.Augeas.csproj @@ -15,7 +15,7 @@ root\%(RecursiveDir)\%(Filename)%(Extension) - + PreserveNewest diff --git a/Sharp.Augeas/Tree/Argument.cs b/Sharp.Augeas/Tree/Argument.cs new file mode 100644 index 0000000..e0eadea --- /dev/null +++ b/Sharp.Augeas/Tree/Argument.cs @@ -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; + } +} \ No newline at end of file diff --git a/Sharp.Augeas/Tree/Directive.cs b/Sharp.Augeas/Tree/Directive.cs new file mode 100644 index 0000000..3cb6f42 --- /dev/null +++ b/Sharp.Augeas/Tree/Directive.cs @@ -0,0 +1,74 @@ +using System.Text; + +namespace Sharp.Augeas; + +public class Directive : Node +{ + public string Value; + public List Arguments; + public bool HasArguments => Arguments.Count != 0; + + /// + /// 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. + /// + /// + 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]); + } + } + + /// + /// Set the value of this directive. + /// Note: This doesn't write any changes to disk. + /// + /// New value. + /// + 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(); + } + + /// + /// Add a argument to this node. + /// + /// + 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(); + } +} \ No newline at end of file diff --git a/Sharp.Augeas/Tree/Node.cs b/Sharp.Augeas/Tree/Node.cs new file mode 100644 index 0000000..090115f --- /dev/null +++ b/Sharp.Augeas/Tree/Node.cs @@ -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(); + } + +} \ No newline at end of file diff --git a/Sharp.Augeas/Tree/SuperNode.cs b/Sharp.Augeas/Tree/SuperNode.cs new file mode 100644 index 0000000..fec60f4 --- /dev/null +++ b/Sharp.Augeas/Tree/SuperNode.cs @@ -0,0 +1,56 @@ +using System.Text; + +namespace Sharp.Augeas +{ + public class SuperNode : Node + { + public List Directives; + public List Arguments; + public List SuperNodes; + + public SuperNode(Augeas augeas, string path, string id) : base(augeas, path) + { + Path = path; + Id = id; + Directives = new List(); + Arguments = new List(); + SuperNodes = new List(); + } + + 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();; + } + } +} + diff --git a/Sharp.Augeas/Tree/TreeExtensions.cs b/Sharp.Augeas/Tree/TreeExtensions.cs new file mode 100644 index 0000000..6748d45 --- /dev/null +++ b/Sharp.Augeas/Tree/TreeExtensions.cs @@ -0,0 +1,119 @@ +using System.Text; + +namespace Sharp.Augeas; + +public static class TreeExtensions +{ + /// + /// Builds a typed tree with the + /// + /// + /// Super node name. + /// Augeas path. + /// + public static SuperNode GetTree(this Augeas augeas, string superNodeName, string augeasPath) + { + var basePath = augeasPath.Replace("*", ""); + var tree = augeas.GetDictionaryTree(augeasPath); + Dictionary addedDirectives = new Dictionary(); + Dictionary addedSuperNodes = new Dictionary(); + 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"); + } + +} \ No newline at end of file diff --git a/Sharp.Augeas/VirtualHost/ApacheConfigExtensions.cs b/Sharp.Augeas/VirtualHost/ApacheConfigExtensions.cs deleted file mode 100644 index 76e6819..0000000 --- a/Sharp.Augeas/VirtualHost/ApacheConfigExtensions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Sharp.Augeas; - -public static class ApacheConfigExtensions -{ - -} \ No newline at end of file diff --git a/Sharp.Augeas/VirtualHost/Argument.cs b/Sharp.Augeas/VirtualHost/Argument.cs deleted file mode 100644 index 05af516..0000000 --- a/Sharp.Augeas/VirtualHost/Argument.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Sharp.Augeas; - -public class Argument : 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() - { - - } -} \ No newline at end of file diff --git a/Sharp.Augeas/VirtualHost/Directive.cs b/Sharp.Augeas/VirtualHost/Directive.cs deleted file mode 100644 index c97f8e7..0000000 --- a/Sharp.Augeas/VirtualHost/Directive.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Sharp.Augeas; - -public class Directive : Node -{ - public string Value; - public List Arguments; -} \ No newline at end of file diff --git a/Sharp.Augeas/VirtualHost/Node.cs b/Sharp.Augeas/VirtualHost/Node.cs deleted file mode 100644 index 3babfe9..0000000 --- a/Sharp.Augeas/VirtualHost/Node.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Sharp.Augeas; - -public class Node -{ - public Node Parent; - public List Children; - - - public Node() - { - Parent = null; - Children = new List(); - } - public Node(Node parent) - { - Parent = parent; - Children = new List(); - } - - public T[] GetChildren() - { - return Children - .OfType() - .ToArray(); - } - - public Node(Node parent, List 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(); - } -} \ No newline at end of file diff --git a/Sharp.Augeas/VirtualHost/Proxy.cs b/Sharp.Augeas/VirtualHost/Proxy.cs deleted file mode 100644 index 7d8f0aa..0000000 --- a/Sharp.Augeas/VirtualHost/Proxy.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Sharp.Augeas; - -public class Proxy : Node -{ - public new VirtualHost Parent; - public List> Directives; - public List> Arguments; -} \ No newline at end of file diff --git a/Sharp.Augeas/VirtualHost/VirtualHost.cs b/Sharp.Augeas/VirtualHost/VirtualHost.cs deleted file mode 100644 index 538cf63..0000000 --- a/Sharp.Augeas/VirtualHost/VirtualHost.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Sharp.Augeas -{ - public class VirtualHost : Node - { - public List> Directives; - public List> Arguments; - } -} - diff --git a/Sharp.Augeas/VirtualHostTreeGenerator.cs b/Sharp.Augeas/VirtualHostTreeGenerator.cs deleted file mode 100644 index 073129a..0000000 --- a/Sharp.Augeas/VirtualHostTreeGenerator.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Sharp.Augeas; - -public static class VirtualHostTreeGenerator -{ - public static VirtualHost Generate(Dictionary 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"); - } - -} \ No newline at end of file