diff options
| author | John Estabrook <jestabro@vyos.io> | 2025-12-17 11:54:20 -0600 |
|---|---|---|
| committer | John Estabrook <jestabro@vyos.io> | 2025-12-17 21:29:58 -0600 |
| commit | f58bfaa3487ef821466e35fbd2bb073732e889dd (patch) | |
| tree | c1c340dc190d2595cc1e1ec8447f163ce56610b2 /src | |
| parent | 28b6ac04aaef995656eaabb2c9a279a79e657687 (diff) | |
| download | vyconf-f58bfaa3487ef821466e35fbd2bb073732e889dd.tar.gz vyconf-f58bfaa3487ef821466e35fbd2bb073732e889dd.zip | |
T8061: add get_completion_env request
Return help strings and values in the form used by bash completion.
Diffstat (limited to 'src')
| -rw-r--r-- | src/session.ml | 14 | ||||
| -rw-r--r-- | src/session.mli | 2 | ||||
| -rw-r--r-- | src/vyconf_cli_compat.ml | 9 | ||||
| -rw-r--r-- | src/vyconf_client.ml | 9 | ||||
| -rw-r--r-- | src/vyconf_client.mli | 2 | ||||
| -rw-r--r-- | src/vyconf_pbt.ml | 72 | ||||
| -rw-r--r-- | src/vyconf_pbt.mli | 22 | ||||
| -rw-r--r-- | src/vyconfd.ml | 12 |
8 files changed, 141 insertions, 1 deletions
diff --git a/src/session.ml b/src/session.ml index f924591..0bd3d95 100644 --- a/src/session.ml +++ b/src/session.ml @@ -397,6 +397,20 @@ let reference_path_exists w _s path = let get_path_type ?(legacy_format=false) w _s path = RT.get_path_type_str ~legacy_format w.reference_tree path +let get_completion_env ?(legacy_format=false) w s path = + let op, path = + match path with + | [] -> raise (Session_error "Missing op and path") + | h :: tl -> (h, tl) + in + let config = get_proposed_config w s in + let res = + Vyos1x.Completion.get_completion_env_str ~legacy_format w.reference_tree config op path + in + match res with + | Ok env -> env + | Error e -> raise (Session_error e) + let write_running_cache w = (* alert exn Internal.write_internal: [Internal.Write_error] caught diff --git a/src/session.mli b/src/session.mli index 5209878..9711402 100644 --- a/src/session.mli +++ b/src/session.mli @@ -98,3 +98,5 @@ val show_config : world -> session_data -> string list -> string val reference_path_exists : world -> session_data -> string list -> bool val get_path_type : ?legacy_format:bool -> world -> session_data -> string list -> string + +val get_completion_env : ?legacy_format:bool -> world -> session_data -> string list -> string diff --git a/src/vyconf_cli_compat.ml b/src/vyconf_cli_compat.ml index c86ca2c..eb14136 100644 --- a/src/vyconf_cli_compat.ml +++ b/src/vyconf_cli_compat.ml @@ -12,6 +12,7 @@ type op_t = | OpConfigUnsaved | OpReferencePathExists | OpGetPathType + | OpGetCompletionEnv let op_of_arg s = match s with @@ -25,6 +26,7 @@ let op_of_arg s = | "sessionUnsaved" -> OpConfigUnsaved | "validateTmplPath" -> OpReferencePathExists | "getNodeType" -> OpGetPathType + | "getCompletionEnv" -> OpGetCompletionEnv | _ -> failwith (Printf.sprintf "Unknown operation %s" s) let in_cli_config_session () = @@ -97,6 +99,7 @@ let main op path = | OpConfigUnsaved -> config_unsaved c None | OpReferencePathExists -> reference_path_exists c path | OpGetPathType -> get_path_type c path + | OpGetCompletionEnv -> get_completion_env c path end | Error e -> Error e |> Lwt.return in @@ -134,7 +137,11 @@ let () = with Failure msg -> let () = print_endline msg in exit 1 in match op, path_list with - | OpSetEditLevel, [] | OpReferencePathExists, [] | OpGetPathType, [] -> + | OpSetEditLevel, [] + | OpReferencePathExists, [] + | OpGetPathType, [] -> let () = print_endline "Must specify config path" in exit 1 + | OpGetCompletionEnv, [] | OpGetCompletionEnv, [_] -> + let () = print_endline "Must specify command and at least one component" in exit 1 | _, _ -> let result = Lwt_main.run (main op path_list) in exit result diff --git a/src/vyconf_client.ml b/src/vyconf_client.ml index 8a8dc46..6b6c6f1 100644 --- a/src/vyconf_client.ml +++ b/src/vyconf_client.ml @@ -245,3 +245,12 @@ let get_path_type client path = | Success -> unwrap resp.output |> Lwt.return | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return + +let get_completion_env client path = + let req = Get_completion_env {path=path; legacy_format=true;} in + let%lwt resp = do_request client req in + match resp.status with + | Success -> unwrap resp.output |> Lwt.return + (* legacy getCompletionEnv is silent on error *) + | Fail -> Error "" |> Lwt.return + | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return diff --git a/src/vyconf_client.mli b/src/vyconf_client.mli index fabbbed..3ee1083 100644 --- a/src/vyconf_client.mli +++ b/src/vyconf_client.mli @@ -53,3 +53,5 @@ val config_unsaved : t -> string option -> (string, string) result Lwt.t val reference_path_exists : t -> string list -> (string, string) result Lwt.t val get_path_type : t -> string list -> (string, string) result Lwt.t + +val get_completion_env : t -> string list -> (string, string) result Lwt.t diff --git a/src/vyconf_pbt.ml b/src/vyconf_pbt.ml index 9e5873f..939af0c 100644 --- a/src/vyconf_pbt.ml +++ b/src/vyconf_pbt.ml @@ -192,6 +192,11 @@ type request_get_path_type = { legacy_format : bool; } +type request_get_completion_env = { + path : string list; + legacy_format : bool; +} + type request = | Prompt | Setup_session of request_setup_session @@ -233,6 +238,7 @@ type request = | Config_unsaved of request_config_unsaved | Reference_path_exists of request_reference_path_exists | Get_path_type of request_get_path_type + | Get_completion_env of request_get_completion_env type request_envelope = { token : string option; @@ -550,6 +556,14 @@ let rec default_request_get_path_type legacy_format; } +let rec default_request_get_completion_env + ?path:((path:string list) = []) + ?legacy_format:((legacy_format:bool) = false) + () : request_get_completion_env = { + path; + legacy_format; +} + let rec default_request (): request = Prompt let rec default_request_envelope @@ -930,6 +944,16 @@ let default_request_get_path_type_mutable () : request_get_path_type_mutable = { legacy_format = false; } +type request_get_completion_env_mutable = { + mutable path : string list; + mutable legacy_format : bool; +} + +let default_request_get_completion_env_mutable () : request_get_completion_env_mutable = { + path = []; + legacy_format = false; +} + type request_envelope_mutable = { mutable token : string option; mutable request : request; @@ -1238,6 +1262,13 @@ let rec pp_request_get_path_type fmt (v:request_get_path_type) = in Pbrt.Pp.pp_brk pp_i fmt () +let rec pp_request_get_completion_env fmt (v:request_get_completion_env) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "path" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.path; + Pbrt.Pp.pp_record_field ~first:false "legacy_format" Pbrt.Pp.pp_bool fmt v.legacy_format; + in + Pbrt.Pp.pp_brk pp_i fmt () + let rec pp_request fmt (v:request) = match v with | Prompt -> Format.fprintf fmt "Prompt" @@ -1280,6 +1311,7 @@ let rec pp_request fmt (v:request) = | Config_unsaved x -> Format.fprintf fmt "@[<hv2>Config_unsaved(@,%a)@]" pp_request_config_unsaved x | Reference_path_exists x -> Format.fprintf fmt "@[<hv2>Reference_path_exists(@,%a)@]" pp_request_reference_path_exists x | Get_path_type x -> Format.fprintf fmt "@[<hv2>Get_path_type(@,%a)@]" pp_request_get_path_type x + | Get_completion_env x -> Format.fprintf fmt "@[<hv2>Get_completion_env(@,%a)@]" pp_request_get_completion_env x let rec pp_request_envelope fmt (v:request_envelope) = let pp_i fmt () = @@ -1732,6 +1764,15 @@ let rec encode_pb_request_get_path_type (v:request_get_path_type) encoder = Pbrt.Encoder.key 2 Pbrt.Varint encoder; () +let rec encode_pb_request_get_completion_env (v:request_get_completion_env) encoder = + Pbrt.List_util.rev_iter_with (fun x encoder -> + Pbrt.Encoder.string x encoder; + Pbrt.Encoder.key 1 Pbrt.Bytes encoder; + ) v.path encoder; + Pbrt.Encoder.bool v.legacy_format encoder; + Pbrt.Encoder.key 2 Pbrt.Varint encoder; + () + let rec encode_pb_request (v:request) encoder = begin match v with | Prompt -> @@ -1854,6 +1895,9 @@ let rec encode_pb_request (v:request) encoder = | Get_path_type x -> Pbrt.Encoder.nested encode_pb_request_get_path_type x encoder; Pbrt.Encoder.key 40 Pbrt.Bytes encoder; + | Get_completion_env x -> + Pbrt.Encoder.nested encode_pb_request_get_completion_env x encoder; + Pbrt.Encoder.key 41 Pbrt.Bytes encoder; end let rec encode_pb_request_envelope (v:request_envelope) encoder = @@ -2840,6 +2884,33 @@ let rec decode_pb_request_get_path_type d = legacy_format = v.legacy_format; } : request_get_path_type) +let rec decode_pb_request_get_completion_env d = + let v = default_request_get_completion_env_mutable () in + let continue__= ref true in + let legacy_format_is_set = ref false in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.path <- List.rev v.path; + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.path <- (Pbrt.Decoder.string d) :: v.path; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_get_completion_env), field(1)" pk + | Some (2, Pbrt.Varint) -> begin + v.legacy_format <- Pbrt.Decoder.bool d; legacy_format_is_set := true; + end + | Some (2, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_get_completion_env), field(2)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + begin if not !legacy_format_is_set then Pbrt.Decoder.missing_field "legacy_format" end; + ({ + path = v.path; + legacy_format = v.legacy_format; + } : request_get_completion_env) + let rec decode_pb_request d = let rec loop () = let ret:request = match Pbrt.Decoder.key d with @@ -2893,6 +2964,7 @@ let rec decode_pb_request d = | Some (38, _) -> (Config_unsaved (decode_pb_request_config_unsaved (Pbrt.Decoder.nested d)) : request) | Some (39, _) -> (Reference_path_exists (decode_pb_request_reference_path_exists (Pbrt.Decoder.nested d)) : request) | Some (40, _) -> (Get_path_type (decode_pb_request_get_path_type (Pbrt.Decoder.nested d)) : request) + | Some (41, _) -> (Get_completion_env (decode_pb_request_get_completion_env (Pbrt.Decoder.nested d)) : request) | Some (n, payload_kind) -> ( Pbrt.Decoder.skip d payload_kind; loop () diff --git a/src/vyconf_pbt.mli b/src/vyconf_pbt.mli index 5c71016..2558dc0 100644 --- a/src/vyconf_pbt.mli +++ b/src/vyconf_pbt.mli @@ -199,6 +199,11 @@ type request_get_path_type = { legacy_format : bool; } +type request_get_completion_env = { + path : string list; + legacy_format : bool; +} + type request = | Prompt | Setup_session of request_setup_session @@ -240,6 +245,7 @@ type request = | Config_unsaved of request_config_unsaved | Reference_path_exists of request_reference_path_exists | Get_path_type of request_get_path_type + | Get_completion_env of request_get_completion_env type request_envelope = { token : string option; @@ -535,6 +541,13 @@ val default_request_get_path_type : request_get_path_type (** [default_request_get_path_type ()] is the default value for type [request_get_path_type] *) +val default_request_get_completion_env : + ?path:string list -> + ?legacy_format:bool -> + unit -> + request_get_completion_env +(** [default_request_get_completion_env ()] is the default value for type [request_get_completion_env] *) + val default_request : unit -> request (** [default_request ()] is the default value for type [request] *) @@ -686,6 +699,9 @@ val pp_request_reference_path_exists : Format.formatter -> request_reference_pat val pp_request_get_path_type : Format.formatter -> request_get_path_type -> unit (** [pp_request_get_path_type v] formats v *) +val pp_request_get_completion_env : Format.formatter -> request_get_completion_env -> unit +(** [pp_request_get_completion_env v] formats v *) + val pp_request : Format.formatter -> request -> unit (** [pp_request v] formats v *) @@ -827,6 +843,9 @@ val encode_pb_request_reference_path_exists : request_reference_path_exists -> P val encode_pb_request_get_path_type : request_get_path_type -> Pbrt.Encoder.t -> unit (** [encode_pb_request_get_path_type v encoder] encodes [v] with the given [encoder] *) +val encode_pb_request_get_completion_env : request_get_completion_env -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_get_completion_env v encoder] encodes [v] with the given [encoder] *) + val encode_pb_request : request -> Pbrt.Encoder.t -> unit (** [encode_pb_request v encoder] encodes [v] with the given [encoder] *) @@ -968,6 +987,9 @@ val decode_pb_request_reference_path_exists : Pbrt.Decoder.t -> request_referenc val decode_pb_request_get_path_type : Pbrt.Decoder.t -> request_get_path_type (** [decode_pb_request_get_path_type decoder] decodes a [request_get_path_type] binary value from [decoder] *) +val decode_pb_request_get_completion_env : Pbrt.Decoder.t -> request_get_completion_env +(** [decode_pb_request_get_completion_env decoder] decodes a [request_get_completion_env] binary value from [decoder] *) + val decode_pb_request : Pbrt.Decoder.t -> request (** [decode_pb_request decoder] decodes a [request] binary value from [decoder] *) diff --git a/src/vyconfd.ml b/src/vyconfd.ml index 96c2e42..d34deab 100644 --- a/src/vyconfd.ml +++ b/src/vyconfd.ml @@ -433,6 +433,17 @@ let get_path_type world token (req: request_get_path_type) = with Session.Session_error msg -> {response_tmpl with status=Fail; error=(Some msg)} +let get_completion_env world token (req: request_get_completion_env) = + let s = find_session token in + try + let node_type = + Session.get_completion_env + ~legacy_format:req.legacy_format world s req.path + in + {response_tmpl with output=(Some node_type)} + with Session.Session_error msg -> + {response_tmpl with status=Fail; error=(Some msg)} + let send_response oc resp = let enc = Pbrt.Encoder.create () in let%lwt () = encode_pb_response resp enc |> return in @@ -492,6 +503,7 @@ let rec handle_connection world ic oc () = | Some t, Config_unsaved r -> config_unsaved world t r | Some t, Reference_path_exists r -> reference_path_exists world t r | Some t, Get_path_type r -> get_path_type world t r + | Some t, Get_completion_env r -> get_completion_env world t r | _ -> failwith "Unimplemented" ) |> Lwt.return end |
