Skip to content

CP-47356: Support backwards capability for Go SDK #5620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 14, 2024
Merged
10 changes: 4 additions & 6 deletions ocaml/sdk-gen/common/CommonFunctions.ml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ let rec lifecycle_matcher milestone lifecycle =
else
lifecycle_matcher milestone tl

let get_published_release_for_param releases =
let published_release_for_param releases =
let filtered =
List.filter
(fun x -> x <> "closed" && x <> "3.0.3" && x <> "debug")
Expand Down Expand Up @@ -138,8 +138,8 @@ let get_release_branding codename =
let group_params_per_release params =
let same_release p1 p2 =
compare_versions
(get_published_release_for_param p1.param_release.internal)
(get_published_release_for_param p2.param_release.internal)
(published_release_for_param p1.param_release.internal)
(published_release_for_param p2.param_release.internal)
= 0
in
let rec groupByRelease acc = function
Expand Down Expand Up @@ -240,9 +240,7 @@ and get_deprecated_info_message message =

and get_published_info_param message param =
let msgRelease = get_published_release message.msg_lifecycle.transitions in
let paramRelease =
get_published_release_for_param param.param_release.internal
in
let paramRelease = published_release_for_param param.param_release.internal in
if compare_versions paramRelease msgRelease > 0 then
sprintf "First published in %s." (get_release_branding paramRelease)
else
Expand Down
9 changes: 9 additions & 0 deletions ocaml/sdk-gen/common/CommonFunctions.mli
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,15 @@ val session_id : param
val objects : obj list
(** Objects of api that generate SDKs. *)

val published_release_for_param : string list -> string

val compare_versions : string -> string -> int
(** Compare two published releases.
@param published release r1.
@param published release r2.
@return the order diff between r1 and r2.
*)

module TypesOfMessages : sig
val of_params : Datamodel_types.obj list -> Datamodel_types.ty list
(** All the types in the params of messages*)
Expand Down
216 changes: 142 additions & 74 deletions ocaml/sdk-gen/go/gen_go_helper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -250,40 +250,95 @@ module Json = struct
; ("func_name_suffix", `String (suffix_of_type t))
]

let of_params params =
let name_internal name =
let name = name |> snake_to_camel |> String.uncapitalize_ascii in
match name with "type" -> "typeKey" | "interface" -> "inter" | _ -> name
let group_params msg =
let published_release releases =
match (published_release_for_param releases, releases) with
| "", [rel] ->
rel
| rel, _ ->
rel
in
let of_param param =
let suffix_of_type = suffix_of_type param.param_type in
let t, _e = string_of_ty_with_enums param.param_type in
let name = param.param_name in
[
("is_session_id", `Bool (name = "session_id"))
; ("type", `String t)
; ("name", `String name)
; ("name_internal", `String (name_internal name))
; ("doc", `String param.param_doc)
; ("func_name_suffix", `String suffix_of_type)
]
let do_group params =
let params =
List.map
(fun p -> (published_release p.param_release.internal, p))
params
in
let uniq_sorted_rels =
List.map fst params
|> Listext.List.setify
|> List.fast_sort compare_versions
in
List.map
(fun rel ->
let params =
List.filter_map
(fun (r, param) ->
match compare_versions r rel with
| n when n > 0 ->
None
| _ ->
Some param
)
params
in
(params, rel)
)
uniq_sorted_rels
in
let only_session_group =
[([session_id], published_release msg.msg_release.internal)]
in
(* We use ',' to seprate params in Go function, we should ignore ',' before first param,
for example `func(a type1, b type2)` is wanted rather than `func(, a type1, b type2)`.
let groups =
match (msg.msg_session, do_group msg.msg_params) with
| true, [] ->
only_session_group
| true, groups ->
List.map (fun (params, rel) -> (session_id :: params, rel)) groups
| false, groups ->
groups
in
(* The bool label in the tuple below is tagged to distinguish whether it is the latest parameters group.
If it's the latest parameters group, then we should not add the number of parameters to the method's name.
*)
let add_first = function
| head :: rest ->
let head = `O (("first", `Bool true) :: of_param head) in
let rest =
List.map
(fun item -> `O (("first", `Bool false) :: of_param item))
rest
in
head :: rest
| [] ->
[]
match List.rev groups with
| (params, rel) :: _ as groups ->
(true, params, rel)
:: List.map (fun (params, rel) -> (false, params, rel)) groups
| [] ->
failwith "Empty params group should not exist."

let of_param param =
let name_internal name =
let name = name |> snake_to_camel |> String.uncapitalize_ascii in
match name with "type" -> "typeKey" | "interface" -> "inter" | _ -> name
in
`A (add_first params)
let suffix_of_type = suffix_of_type param.param_type in
let t, _e = string_of_ty_with_enums param.param_type in
let name = param.param_name in
[
("is_session_id", `Bool (name = "session_id"))
; ("type", `String t)
; ("name", `String name)
; ("name_internal", `String (name_internal name))
; ("doc", `String param.param_doc)
; ("func_name_suffix", `String suffix_of_type)
]

(* We use ',' to seprate params in Go function, we should ignore ',' before first param,
for example `func(a type1, b type2)` is wanted rather than `func(, a type1, b type2)`.
*)
let of_params = function
| head :: rest ->
let head = `O (("first", `Bool true) :: of_param head) in
let rest =
List.map
(fun item -> `O (("first", `Bool false) :: of_param item))
rest
in
head :: rest
| [] ->
[]

let of_error e = `O [("name", `String e.err_name); ("doc", `String e.err_doc)]

Expand All @@ -293,16 +348,6 @@ module Json = struct
| errors ->
`A (List.map of_error errors)

let add_session_info class_name method_name =
match (class_name, method_name) with
| "session", "login_with_password"
| "session", "slave_local_login_with_password" ->
[("session_login", `Bool true); ("session_logout", `Bool false)]
| "session", "logout" | "session", "local_logout" ->
[("session_login", `Bool false); ("session_logout", `Bool true)]
| _ ->
[("session_login", `Bool false); ("session_logout", `Bool false)]

let desc_of_msg msg ctor_fields =
let ctor =
if msg.msg_tag = FromObject Make then
Expand Down Expand Up @@ -331,42 +376,65 @@ module Json = struct
)
|> String.concat ", "

let method_name_exported method_name params latest =
let method_name = snake_to_camel method_name in
if latest then
method_name
else
method_name ^ string_of_int (List.length params)

(* Since the param of `session *Session` isn't needed in functions of session object,
we add a special "func_params" field for session object to ignore `session *Session`.*)
let addtion_info_of_session method_name params latest =
let add_session_info method_name =
match method_name with
| "login_with_password" | "slave_local_login_with_password" ->
[("session_login", `Bool true); ("session_logout", `Bool false)]
| "logout" | "local_logout" ->
[("session_login", `Bool false); ("session_logout", `Bool true)]
| _ ->
[("session_login", `Bool false); ("session_logout", `Bool false)]
in
let name = method_name_exported method_name params latest in
("func_params", `A (of_params params))
:: ("method_name_exported", `String name)
:: add_session_info method_name

let addtion_info msg params latest =
let method_name = msg.msg_name in
match (String.lowercase_ascii msg.msg_obj_name, msg.msg_session) with
| "session", true ->
addtion_info_of_session method_name (List.tl params) latest
| "session", false ->
addtion_info_of_session method_name params latest
| _ ->
let name = method_name_exported method_name params latest in
[("method_name_exported", `String name)]

let messages_of_obj obj =
let ctor_fields = ctor_fields_of_obj obj in
let params_in_msg msg =
if msg.msg_session then
session_id :: msg.msg_params
else
msg.msg_params
in
List.map
(fun msg ->
let params = params_in_msg msg |> of_params in
let base_assoc_list =
[
("method_name", `String msg.msg_name)
; ("class_name", `String obj.name)
; ("class_name_exported", `String (snake_to_camel obj.name))
; ("method_name_exported", `String (snake_to_camel msg.msg_name))
; ("description", desc_of_msg msg ctor_fields)
; ("result", of_result obj msg)
; ("params", params)
; ("errors", of_errors msg.msg_errors)
; ("has_error", `Bool (msg.msg_errors <> []))
; ("async", `Bool msg.msg_async)
]
in
(* Since the param of `session *Session` isn't needed in functions of session object,
we add a special "func_params" field for session object to ignore `session *Session`.*)
if obj.name = "session" then
`O
(("func_params", msg.msg_params |> of_params)
:: (add_session_info obj.name msg.msg_name @ base_assoc_list)
)
else
`O base_assoc_list
)
obj.messages
obj.messages
|> List.rev_map (fun msg ->
let of_message (latest, params, rel_version) =
let base_assoc_list =
[
("method_name", `String msg.msg_name)
; ("class_name", `String obj.name)
; ("class_name_exported", `String (snake_to_camel obj.name))
; ("description", desc_of_msg msg ctor_fields)
; ("result", of_result obj msg)
; ("params", `A (of_params params))
; ("errors", of_errors msg.msg_errors)
; ("has_error", `Bool (msg.msg_errors <> []))
; ("async", `Bool msg.msg_async)
; ("version", `String rel_version)
]
in
`O (base_assoc_list @ addtion_info msg params latest)
in
msg |> group_params |> List.map of_message
)
|> List.concat

let of_option ty =
let name, _ = string_of_ty_with_enums ty in
Expand Down
3 changes: 3 additions & 0 deletions ocaml/sdk-gen/go/gen_go_helper.mli
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ module Json : sig

val string_of_ty_with_enums : Datamodel_types.ty -> string * enums

val group_params :
Datamodel_types.message -> (bool * Datamodel_types.param list * string) list

val xenapi : Datamodel_types.obj list -> (string * Mustache.Json.t) list

val all_enums : Datamodel_types.obj list -> Mustache.Json.t
Expand Down
2 changes: 2 additions & 0 deletions ocaml/sdk-gen/go/templates/Methods.mustache
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{{#messages}}
// {{method_name_exported}}:{{#description}} {{.}}{{/description}}
{{#version}}// Version: {{.}}{{/version}}
{{#has_error}}
//
// Errors:
Expand Down Expand Up @@ -27,6 +28,7 @@ func ({{name_internal}}) {{method_name_exported}}({{#params}}{{#first}}session *

{{#async}}
// Async{{method_name_exported}}:{{#description}} {{.}}{{/description}}
{{#version}}// Version: {{.}}{{/version}}
{{#has_error}}
//
// Errors:
Expand Down
2 changes: 2 additions & 0 deletions ocaml/sdk-gen/go/templates/SessionMethod.mustache
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{{#messages}}
// {{method_name_exported}}:{{#description}} {{.}}{{/description}}
{{#version}}// Version: {{.}}{{/version}}
{{#has_error}}
//
// Errors:
Expand Down Expand Up @@ -37,6 +38,7 @@ func (class *Session) {{method_name_exported}}({{#func_params}}{{^first}}, {{/fi

{{#async}}
// Async{{method_name_exported}}:{{#description}} {{.}}{{/description}}
{{#version}}// Version: {{.}}{{/version}}
{{#has_error}}
//
// Errors:
Expand Down
2 changes: 2 additions & 0 deletions ocaml/sdk-gen/go/test_data/methods.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// GetLog: GetLog Get the host log file
// Version: miami
func (host) GetLog(session *Session, host HostRef) (retval string, err error) {
method := "host.get_log"
sessionIDArg, err := serializeSessionRef(fmt.Sprintf("%s(%s)", method, "session_id"), session.ref)
Expand All @@ -18,6 +19,7 @@ func (host) GetLog(session *Session, host HostRef) (retval string, err error) {
}

// AsyncGetLog: GetLog Get the host log file
// Version: miami
func (host) AsyncGetLog(session *Session, host HostRef) (retval TaskRef, err error) {
method := "Async.host.get_log"
sessionIDArg, err := serializeSessionRef(fmt.Sprintf("%s(%s)", method, "session_id"), session.ref)
Expand Down
2 changes: 2 additions & 0 deletions ocaml/sdk-gen/go/test_data/session_method.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// LoginWithPassword: Attempt to authenticate the user); returning a session reference if successful
// Version: miami
//
// Errors:
// SESSION_AUTHENTICATION_FAILED - The credentials given by the user are incorrect
Expand Down Expand Up @@ -26,6 +27,7 @@ func (class *Session) LoginWithPassword(uname string, pwd string) (retval Sessio
}

// Logout: Logout Log out of a session
// Version: miami
func (class *Session) Logout() (err error) {
method := "session.logout"
sessionIDArg, err := serializeSessionRef(fmt.Sprintf("%s(%s)", method, "session_id"), class.ref)
Expand Down
Loading
Loading