summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@baturin.org>2018-05-27 22:40:14 +0700
committerDaniil Baturin <daniil@baturin.org>2018-05-27 22:40:14 +0700
commitcb5a0226c3d514896a1818e1681ad9d35eac6fb8 (patch)
tree6f476321f38957dcf57c0dbbb0d283d46d2ebecc /lib
parentc5176efc2817f8a43cd2d28f28dfcfdff249a85c (diff)
downloadlibvyosconfig-cb5a0226c3d514896a1818e1681ad9d35eac6fb8.tar.gz
libvyosconfig-cb5a0226c3d514896a1818e1681ad9d35eac6fb8.zip
Add a formatter for VyOS 1.x config files.
Diffstat (limited to 'lib')
-rw-r--r--lib/vyos1x_renderer.ml82
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/vyos1x_renderer.ml b/lib/vyos1x_renderer.ml
new file mode 100644
index 0000000..4a1f4a0
--- /dev/null
+++ b/lib/vyos1x_renderer.ml
@@ -0,0 +1,82 @@
+(* The renderer makes two assumptions about the invariants of the config files:
+ that top level nodes are never tag or leaf nodes,
+ and that immediate children of tag nodes are never themselves tag nodes.
+
+ They are true in all existing VyOS configs and configs with those invariant
+ broken will never load, so these assumptions are safe to make when
+ processing existing configs. In configs built from scratch, the user is
+ responsible for its validness.
+
+ The original loader behaviour with tag nodes is strange: deep down, after
+ config loading, they are indistinguishable from any other nodes, but at load
+ time, they fail to validate unless they are formatted as tag nodes in the
+ config file, that is, "ethernet eth0 { ..." as opposed to "ethernet { eth0 { ...".
+
+ Since Vyconf makes no distinction between normal nodes and tag nodes other than
+ at set command validation and formatting time, I reused the ephemeral flag
+ which is never used in VyOS 1.x for marking nodes as tag nodes at parsing time.
+
+ *)
+
+module CT = Config_tree
+module VT = Vytree
+
+let make_indent indent level = String.make (level * indent) ' '
+
+let render_values indent_str name values =
+ match values with
+ | [] -> Printf.sprintf "%s%s { }\n" indent_str name
+ | [v] -> Printf.sprintf "%s%s %s\n" indent_str name v
+ | _ ->
+ let rendered = List.map (fun s -> Printf.sprintf "%s%s %s" indent_str name s) values in
+ String.concat "\n" rendered
+
+let render_comment indent c =
+ match c with
+ | None -> ""
+ | Some c -> Printf.sprintf "%s/* %s */\n" indent c
+
+let rec render_node indent level node =
+ let open CT in
+ let indent_str = make_indent indent level in
+ let name = VT.name_of_node node in
+ let data = VT.data_of_node node in
+ let is_tag = data.ephemeral (* sic! look in the parser *) in
+ let comment = render_comment indent_str data.comment in
+ let values = render_values indent_str name data.values in
+ let children = VT.children_of_node node in
+ match children with
+ | [] -> Printf.sprintf "%s\n%s" comment values
+ | _ ->
+ if is_tag then
+ begin
+ let inner = List.map (render_tag_node indent (level + 1) name) children in
+ String.concat "\n" inner
+ end
+ else
+ begin
+ let inner = List.map (render_node indent (level + 1)) children in
+ let inner = String.concat "\n" inner in
+ Printf.sprintf "%s%s%s {\n%s\n%s}\n" indent_str comment name inner indent_str
+ end
+
+and render_tag_node indent level parent node =
+ let open CT in
+ let indent_str = make_indent indent level in
+ let name = VT.name_of_node node in
+ let data = VT.data_of_node node in
+ let comment = render_comment indent_str data.comment in
+ let values = render_values indent_str name data.values in
+ let children = VT.children_of_node node in
+ match children with
+ | [] -> Printf.sprintf "%s\n%s" comment values
+ | _ ->
+ (* Exploiting the fact that immediate children of tag nodes are
+ never themselves tag nodes *)
+ let inner = List.map (render_node indent (level + 1)) children in
+ let inner = String.concat "\n" inner in
+ Printf.sprintf "%s%s%s %s {\n%s\n%s}\n" indent_str comment parent name inner indent_str
+
+
+
+