diff options
| author | John Estabrook <jestabro@vyos.io> | 2025-10-27 22:42:37 -0500 |
|---|---|---|
| committer | John Estabrook <jestabro@vyos.io> | 2025-11-03 08:11:05 -0600 |
| commit | 2aea7ddbc092b03dbf07dce385786b9c5c16a881 (patch) | |
| tree | 3c837d8e16cb52d1d7bb85ea4afc5ffb913a81d0 /src/config_diff.ml | |
| parent | 6ced0e36b3f98675d82007f8c77193e2836c4b60 (diff) | |
| download | vyos1x-config-2aea7ddbc092b03dbf07dce385786b9c5c16a881.tar.gz vyos1x-config-2aea7ddbc092b03dbf07dce385786b9c5c16a881.zip | |
T7915: add compiler alerts and annotations
Diffstat (limited to 'src/config_diff.ml')
| -rw-r--r-- | src/config_diff.ml | 134 |
1 files changed, 114 insertions, 20 deletions
diff --git a/src/config_diff.ml b/src/config_diff.ml index 73c379b..b0e48d3 100644 --- a/src/config_diff.ml +++ b/src/config_diff.ml @@ -154,26 +154,40 @@ let rec diff (path : string list) (f : 'a diff_func) (res: 'a result) ((left_nod (* copy node paths between trees *) let rec clone_path ?(recurse=true) ?(set_values=None) old_root new_root path_done path_remaining = + (* raises: + [Vytree.Nonexistent_path] + alert exn Vytree.get: + [Vytree.Empty_path] not possible as clone_path called by clone with non-empty path + [Vytree.Nonexistent_path] allow raise + alert exn Vytree.insert: + [Vytree.Empty_path] not possible as clone_path called by clone with non-empty path + [Not_found] not possible for postion=Lexical + [Vytree.Duplicate_child] not possible as calls are on path complement + [Vytree.Insert_error] not possible as calls are on path_existing @ [name] + *) match path_remaining with | [] | [_] -> let path_total = path_done @ path_remaining in - let old_node = Vytree.get old_root path_total in + let old_node = (Vytree.get[@alert "-exn"]) old_root path_total in let data = match set_values with | Some v -> { (data_of old_node) with Config_tree.values = v } | None -> data_of old_node in if recurse then - Vytree.insert ~position:Lexical ~children:(children_of old_node) new_root path_total data + (Vytree.insert[@alert "-exn"]) ~position:Lexical ~children:(children_of old_node) new_root path_total data else - Vytree.insert ~position:Lexical new_root path_total data + (Vytree.insert[@alert "-exn"]) ~position:Lexical new_root path_total data | name :: names -> let path_done = path_done @ [name] in - let old_node = Vytree.get old_root path_done in - let new_root = Vytree.insert ~position:Lexical new_root path_done (data_of old_node) in + let old_node = (Vytree.get[@alert "-exn"]) old_root path_done in + let new_root = (Vytree.insert[@alert "-exn"]) ~position:Lexical new_root path_done (data_of old_node) in clone_path ~recurse:recurse ~set_values:set_values old_root new_root path_done names let clone ?(recurse=true) ?(set_values=None) old_root new_root path = + (* raises: + [Vytree.Nonexistent_path] from clone_path + *) match path with | [] -> if recurse then old_root else new_root | _ -> @@ -183,6 +197,12 @@ let clone ?(recurse=true) ?(set_values=None) old_root new_root path = (* define the diff_func *) let decorate_trees ?(recurse=true) (path : string list) (Diff_tree res) (m : change) = + (* raises no exception: + clone will always be called on extant path of left or right + alert exn Vytree.get_values: + [Vytree.Empty_path] not possible as pattern Updated implies non-empty path + [Vytree.Nonexistent_path] not possible as pattern Updated implies path exists + *) match m with | Added -> Diff_tree {res with add = clone res.right res.add path; } | Subtracted -> @@ -192,7 +212,7 @@ let decorate_trees ?(recurse=true) (path : string list) (Diff_tree res) (m : cha Diff_tree {res with inter = clone ~recurse:recurse res.left res.inter path; } | Updated v -> (* if in this case, node at path is guaranteed to exist *) - let ov = Config_tree.get_values res.left path in + let ov = (Config_tree.get_values[@alert "-exn"]) res.left path in match ov, v with | [_], [_] -> Diff_tree {res with sub = clone res.left res.sub path; del = clone res.left res.del path; @@ -236,13 +256,24 @@ let decorate_trees ?(recurse=true) (path : string list) (Diff_tree res) (m : cha (* get sub trees for path-relative comparison *) let tree_at_path path node = + (* raises: + [Vytree.Empty_path] + [Empty_comparison] + alert exn Vytree.get: + [Vytree.Empty_path] allow raise + [Vytree.Nonexistent_path] catch and raise Empty_comparison + *) try - let node = Vytree.get node path in + let node = (Vytree.get[@alert "-exn"]) node path in make Config_tree.default_data "" [node] with Vytree.Nonexistent_path -> raise Empty_comparison (* call recursive diff on config_trees with decorate_trees as the diff_func *) let compare path left right = + (* raises: + [Empty_comparison] from tree_at_path + [Incommensurable] + *) if (name_of left) <> (name_of right) then raise Incommensurable else @@ -254,6 +285,10 @@ let compare path left right = (* wrapper to return diff trees *) let diff_tree path left right = + (* raises: + [Incommensurable], + [Empty_comparison] from compare + *) let trees = compare path left right in let add_node = make Config_tree.default_data "add" (children_of (trees.add)) in let sub_node = make Config_tree.default_data "sub" (children_of (trees.sub)) in @@ -266,9 +301,23 @@ let diff_tree path left right = we need a hybrid tree between the 'del' tree and the 'sub' tree, namely: in case the del tree has a terminal tag node (== all tag values have been removed) add tag node values for proper removal in commit execution - *) + *) let get_tagged_delete_tree dt = + (* alert exn Config_tree.is_tag: + [Vytree.Empty_path] not possible in pattern non-empty path + [Vytree.Nonexistent_path] not possible in fold_tree_with_path + alert exn Vytree.is_terminal_path: + [Vytree.Empty_path] not possible in pattern non-empty path + alert exn Vytree.children_of_path: + [Vytree.Empty_path] not possible in pattern non-empty path + [Vytree.Nonexistent_path] not possible in super-tree of fold_tree_with_path arg + alert exn Vytree.insert: + [Vytree.Empty_path]: not possible since called on pattern path non-empty + [Not_found]: not possible for postion=Lexical + [Vytree.Duplicate_child]: not possible by condition is_terminal_path + [Vytree.Insert_error]: not possible since constructed iteratively from existing path + *) let del_tree = Config_tree.get_subtree dt ["del"] in let sub_tree = Config_tree.get_subtree dt ["sub"] in let f (p, a) _t = @@ -276,10 +325,10 @@ let get_tagged_delete_tree dt = match q with | [] -> (p, a) | _ -> - if Config_tree.is_tag a q && Vytree.is_terminal_path a q then - let children = Vytree.children_of_path sub_tree q in + if (Config_tree.is_tag[@alert "-exn"]) a q && (Vytree.is_terminal_path[@alert "-exn"]) a q then + let children = (Vytree.children_of_path[@alert "-exn"]) sub_tree q in let insert_child path node name = - Vytree.insert ~position:Lexical node (path @ [name]) Config_tree.default_data + (Vytree.insert[@alert "-exn"]) ~position:Lexical node (path @ [name]) Config_tree.default_data in let a' = List.fold_left (insert_child q) a children in (p, a') @@ -307,14 +356,20 @@ let marked_render mark node = String.concat "\n" m let added_lines ?(cmds=false) node path = + (* alert exn Config_tree.render_commands: + [Vytree.Nonexistent_path] not possible on root path + *) if not cmds then marked_render "+ " (tree_at_path path node) else - (Config_tree.render_commands ~op:Set node []) ^ "\n" + ((Config_tree.render_commands[@alert "-exn"]) ~op:Set node []) ^ "\n" let removed_lines ?(cmds=false) node path = + (* alert exn Config_tree.render_commands: + [Vytree.Nonexistent_path] not possible on root path + *) if not cmds then marked_render "- " (tree_at_path path node) else - (Config_tree.render_commands ~op:Delete node []) ^ "\n" + ((Config_tree.render_commands[@alert "-exn"]) ~op:Delete node []) ^ "\n" let order_commands (strl: string) = let l = String.split_on_char '\n' strl in @@ -323,6 +378,12 @@ let order_commands (strl: string) = (String.concat "\n" del) ^ "\n" ^ (String.concat "\n" set) ^ "\n" let unified_diff ?(cmds=false) ?recurse:_ (path : string list) (Diff_string res) (m : change) = + (* raises no exception: + clone will always be called on extant path of left or right + alert exn Vytree.get_values: + [Vytree.Empty_path] not possible as pattern Updated implies non-empty path + [Vytree.Nonexistent_path] not possible as pattern Updated implies path exists + *) let ppath_l = list_but_last path in let ppath_s = @@ -348,7 +409,7 @@ let unified_diff ?(cmds=false) ?recurse:_ (path : string list) (Diff_string res) Diff_string { res with ppath = ppath_l; udiff = str_diff; } | Unchanged -> Diff_string (res) | Updated v -> - let ov = Config_tree.get_values res.left path in + let ov = (Config_tree.get_values[@alert "-exn"]) res.left path in match ov, v with | [_], [_] -> let str_diff = @@ -405,6 +466,10 @@ let compare_at_path_maybe_empty left right path = in (left, right) let show_diff ?(cmds=false) path left right = + (* raises: + [Incommensurable], + [Empty_comparison] from compare_at_path_maybe_empty + *) if (name_of left) <> (name_of right) then raise Incommensurable else @@ -425,19 +490,34 @@ let show_diff ?(cmds=false) path left right = (* mask function; mask applied on right *) let mask_func ?recurse:_ (path : string list) (Diff_tree res) (m : change) = + (* alert exn Vytree.delete: + [Vytree.Empty_path] not possible since Unchanged pattern is only empty path + [Vytree.Nonexistent_path] not possible as called on existing config paths (res.left) + alert exn Vytree.is_terminal_path: + [Vytree.Empty_path] not possible since Unchanged pattern is only empty path + *) match m with | Added -> Diff_tree (res) | Subtracted -> (match path with - | [_] -> Diff_tree {res with left = Vytree.delete res.left path} - | _ -> if not (Vytree.is_terminal_path res.right (list_but_last path)) then - Diff_tree {res with left = Vytree.delete res.left path} - else Diff_tree (res)) + | [_] -> + Diff_tree {res with left = (Vytree.delete[@alert "-exn"]) res.left path} + | _ -> + if not ((Vytree.is_terminal_path[@alert "-exn"]) res.right (list_but_last path)) then + Diff_tree {res with left = (Vytree.delete[@alert "-exn"]) res.left path} + else Diff_tree (res)) | Unchanged -> Diff_tree (res) | Updated _ -> Diff_tree (res) (* call recursive diff with mask_func; mask applied on right *) let mask_tree left right = + (* raises: + [Empty_comparison] from diff + [Incommensurable] + *) + if (name_of left) <> (name_of right) then + raise Incommensurable + else let trees = make_diff_trees left right in let d = diff [] mask_func trees (Option.some left, Option.some right) in @@ -450,14 +530,28 @@ let union_of_values (n : Config_tree.t) (m : Config_tree.t) = ValueS.elements (ValueS.union set_n set_m) let tree_union s t = + (* raises: + [Tree_alg.Incompatible_union] + [Tree_alg.Nonexistent_child] should not be reachable + alert exn Tree_alg.ConfigAlg.tree_union: + [Tree_alg.Incompatible_union] allow raise + [Tree_alg.Nonexistent_child] allow raise; should not be reachable + *) let f u v = let values = union_of_values u v in let data = {(data_of v) with Config_tree.values = values} in Vytree.make_full data (name_of v) (children_of v) in - Tree_alg.ConfigAlg.tree_union s t f + (Tree_alg.ConfigAlg.tree_union[@alert "-exn"]) s t f let tree_merge ?(destructive=false) s t = + (* raises: + [Tree_alg.Incompatible_union] + [Tree_alg.Nonexistent_child] should not be reachable + alert exn Tree_alg.ConfigAlg.tree_union: + [Tree_alg.Incompatible_union] allow raise + [Tree_alg.Nonexistent_child] allow raise; should not be reachable + *) let f u v = let data = match destructive with @@ -465,4 +559,4 @@ let tree_merge ?(destructive=false) s t = | true -> data_of v in Vytree.make_full data (name_of v) (children_of v) in - Tree_alg.ConfigAlg.tree_union s t f + (Tree_alg.ConfigAlg.tree_union[@alert "-exn"]) s t f |
