+let get_opt_default registry unmarshaller ~default key =
+ match get_opt registry unmarshaller key with
+ | None -> default
+ | Some v -> v
+
+let set_opt registry marshaller ~key ~value =
+ match value with
+ | None -> unset registry key
+ | Some value -> set registry ~key ~value:(marshaller value)
+
+let get_list registry unmarshaller key =
+ try
+ List.map unmarshaller (get registry key)
+ with Key_not_found _ -> []
+
+let get_pair registry fst_unmarshaller snd_unmarshaller key =
+ let v = singleton (get registry key) in
+ match Str.split spaces_rex v with
+ | [fst; snd] -> fst_unmarshaller fst, snd_unmarshaller snd
+ | _ -> raise (Type_error "not a pair")
+
+let set_list registry marshaller ~key ~value =
+ List.iter (fun v -> set registry ~key ~value:(marshaller v)) value
+
+type xml_tree =
+ | Cdata of string
+ | Element of string * (string * string) list * xml_tree list
+
+let dot_RE = Str.regexp "\\."
+
+let xml_tree_of_registry registry =
+ let has_child name elements =
+ List.exists
+ (function
+ | Element (_, ["name", name'], _) when name = name' -> true
+ | _ -> false)
+ elements
+ in
+ let rec get_child name = function
+ | [] -> assert false
+ | (Element (_, ["name", name'], _) as child) :: tl when name = name' ->
+ child, tl
+ | hd :: tl ->
+ let child, rest = get_child name tl in
+ child, hd :: rest
+ in
+ let rec add_key path value tree =
+ match path, tree with
+ | [key], Element (name, attrs, children) ->
+ Element (name, attrs,
+ Element ("key", ["name", key],
+ [Cdata (strip_blanks value)]) :: children)
+ | dir :: path, Element (name, attrs, children) ->
+ if has_child dir children then
+ let child, rest = get_child dir children in
+ Element (name, attrs, add_key path value child :: rest)
+ else
+ Element (name, attrs,
+ ((add_key path value (Element ("section", ["name", dir], [])))
+ :: children))
+ | _ -> assert false
+ in
+ Hashtbl.fold
+ (fun k v tree -> add_key ("helm_registry" :: (Str.split dot_RE k)) v tree)
+ registry
+ (Element ("helm_registry", [], []))
+
+let rec stream_of_xml_tree = function
+ | Cdata s -> Xml.xml_cdata s
+ | Element (name, attrs, children) ->
+ Xml.xml_nempty name
+ (List.map (fun (n, v) -> (None, n, v)) attrs)
+ (stream_of_xml_trees children)
+and stream_of_xml_trees = function
+ | [] -> [< >]
+ | hd :: tl -> [< stream_of_xml_tree hd; stream_of_xml_trees tl >]
+
+let save_to registry fname =
+ let token_stream = stream_of_xml_tree (xml_tree_of_registry registry) in