2016-09-08 21:13:10 +04:00
|
|
|
(**************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* Copyright (c) 2014 - 2016. *)
|
|
|
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
|
|
(* *)
|
|
|
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
|
|
|
(* *)
|
|
|
|
(**************************************************************************)
|
|
|
|
|
|
|
|
(* Tezos Command line interface - Local Storage for Configuration *)
|
|
|
|
|
|
|
|
open Lwt
|
|
|
|
open Cli_entries
|
|
|
|
|
|
|
|
module type Entity = sig
|
|
|
|
type t
|
|
|
|
val encoding : t Data_encoding.t
|
2016-12-03 16:05:02 +04:00
|
|
|
val of_source :
|
|
|
|
Client_commands.context ->
|
|
|
|
string -> t Lwt.t
|
|
|
|
val to_source :
|
|
|
|
Client_commands.context ->
|
|
|
|
t -> string Lwt.t
|
2016-09-08 21:13:10 +04:00
|
|
|
val name : string
|
|
|
|
end
|
|
|
|
|
|
|
|
module type Alias = sig
|
|
|
|
type t
|
2016-12-03 16:05:02 +04:00
|
|
|
val load :
|
|
|
|
Client_commands.context ->
|
|
|
|
(string * t) list Lwt.t
|
|
|
|
val find :
|
|
|
|
Client_commands.context ->
|
|
|
|
string -> t Lwt.t
|
|
|
|
val find_opt :
|
|
|
|
Client_commands.context ->
|
|
|
|
string -> t option Lwt.t
|
|
|
|
val rev_find :
|
|
|
|
Client_commands.context ->
|
|
|
|
t -> string option Lwt.t
|
|
|
|
val name :
|
|
|
|
Client_commands.context ->
|
|
|
|
t -> string Lwt.t
|
|
|
|
val mem :
|
|
|
|
Client_commands.context ->
|
|
|
|
string -> bool Lwt.t
|
|
|
|
val add :
|
|
|
|
Client_commands.context ->
|
|
|
|
string -> t -> unit Lwt.t
|
|
|
|
val del :
|
|
|
|
Client_commands.context ->
|
|
|
|
string -> unit Lwt.t
|
2017-03-15 04:27:34 +04:00
|
|
|
val update :
|
|
|
|
Client_commands.context ->
|
|
|
|
string -> t -> unit Lwt.t
|
2016-12-03 16:05:02 +04:00
|
|
|
val save :
|
|
|
|
Client_commands.context ->
|
|
|
|
(string * t) list -> unit Lwt.t
|
2017-03-15 04:27:34 +04:00
|
|
|
val of_source :
|
|
|
|
Client_commands.context ->
|
|
|
|
string -> t Lwt.t
|
2016-12-03 16:05:02 +04:00
|
|
|
val to_source :
|
|
|
|
Client_commands.context ->
|
|
|
|
t -> string Lwt.t
|
2016-09-08 21:13:10 +04:00
|
|
|
val alias_param :
|
2016-11-22 17:23:40 +04:00
|
|
|
?name:string ->
|
2016-09-08 21:13:10 +04:00
|
|
|
?desc:string ->
|
2016-12-03 16:05:02 +04:00
|
|
|
('a, Client_commands.context, 'ret) Cli_entries.params ->
|
|
|
|
(string * t -> 'a, Client_commands.context, 'ret) Cli_entries.params
|
2016-09-08 21:13:10 +04:00
|
|
|
val fresh_alias_param :
|
2016-11-22 17:23:40 +04:00
|
|
|
?name:string ->
|
2016-09-08 21:13:10 +04:00
|
|
|
?desc:string ->
|
2016-12-03 16:05:02 +04:00
|
|
|
('a, Client_commands.context, 'ret) Cli_entries.params ->
|
|
|
|
(string -> 'a, Client_commands.context, 'ret) Cli_entries.params
|
2016-09-08 21:13:10 +04:00
|
|
|
val source_param :
|
2016-11-22 17:23:40 +04:00
|
|
|
?name:string ->
|
2016-09-08 21:13:10 +04:00
|
|
|
?desc:string ->
|
2016-12-03 16:05:02 +04:00
|
|
|
('a, Client_commands.context, 'ret) Cli_entries.params ->
|
|
|
|
(t -> 'a, Client_commands.context, 'ret) Cli_entries.params
|
2016-09-08 21:13:10 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
module Alias = functor (Entity : Entity) -> struct
|
|
|
|
|
2017-03-15 04:17:20 +04:00
|
|
|
open Client_commands
|
|
|
|
|
2016-09-08 21:13:10 +04:00
|
|
|
let encoding =
|
|
|
|
let open Data_encoding in
|
|
|
|
list (obj2
|
|
|
|
(req "name" string)
|
|
|
|
(req "value" Entity.encoding))
|
|
|
|
|
2017-03-15 04:17:20 +04:00
|
|
|
let dirname cctxt =
|
|
|
|
cctxt.config.base_dir
|
|
|
|
|
|
|
|
let filename cctxt =
|
|
|
|
Filename.concat (dirname cctxt) (Entity.name ^ "s")
|
2016-09-08 21:13:10 +04:00
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let load cctxt =
|
2017-03-15 04:17:20 +04:00
|
|
|
let filename = filename cctxt in
|
2016-09-08 21:13:10 +04:00
|
|
|
if not (Sys.file_exists filename) then return [] else
|
2016-12-01 21:27:53 +04:00
|
|
|
Data_encoding_ezjsonm.read_file filename >>= function
|
2017-01-23 14:09:45 +04:00
|
|
|
| Error _ ->
|
2016-12-03 16:05:02 +04:00
|
|
|
cctxt.Client_commands.error
|
|
|
|
"couldn't to read the %s alias file" Entity.name
|
2017-01-23 14:09:45 +04:00
|
|
|
| Ok json ->
|
2016-09-08 21:13:10 +04:00
|
|
|
match Data_encoding.Json.destruct encoding json with
|
|
|
|
| exception _ -> (* TODO print_error *)
|
2016-12-03 16:05:02 +04:00
|
|
|
cctxt.Client_commands.error
|
|
|
|
"didn't understand the %s alias file" Entity.name
|
2016-09-08 21:13:10 +04:00
|
|
|
| list ->
|
|
|
|
return list
|
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let find_opt cctxt name =
|
|
|
|
load cctxt >>= fun list ->
|
2016-09-08 21:13:10 +04:00
|
|
|
try return (Some (List.assoc name list))
|
|
|
|
with Not_found -> return None
|
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let find cctxt name =
|
|
|
|
load cctxt >>= fun list ->
|
2016-09-08 21:13:10 +04:00
|
|
|
try return (List.assoc name list)
|
2016-12-03 16:05:02 +04:00
|
|
|
with Not_found ->
|
|
|
|
cctxt.Client_commands.error "no %s alias named %s" Entity.name name
|
2016-09-08 21:13:10 +04:00
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let rev_find cctxt v =
|
|
|
|
load cctxt >>= fun list ->
|
2016-09-08 21:13:10 +04:00
|
|
|
try return (Some (List.find (fun (_, v') -> v = v') list |> fst))
|
|
|
|
with Not_found -> return None
|
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let mem cctxt name =
|
|
|
|
load cctxt >>= fun list ->
|
2016-09-08 21:13:10 +04:00
|
|
|
try
|
|
|
|
ignore (List.assoc name list) ;
|
|
|
|
Lwt.return true
|
|
|
|
with
|
|
|
|
| Not_found -> Lwt.return false
|
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let save cctxt list =
|
2016-09-08 21:13:10 +04:00
|
|
|
catch
|
|
|
|
(fun () ->
|
2017-03-15 04:17:20 +04:00
|
|
|
let dirname = dirname cctxt in
|
2016-12-01 21:27:53 +04:00
|
|
|
(if not (Sys.file_exists dirname) then Lwt_utils.create_dir dirname
|
2016-09-08 21:13:10 +04:00
|
|
|
else return ()) >>= fun () ->
|
2017-03-15 04:17:20 +04:00
|
|
|
let filename = filename cctxt in
|
2016-09-08 21:13:10 +04:00
|
|
|
let json = Data_encoding.Json.construct encoding list in
|
2016-12-01 21:27:53 +04:00
|
|
|
Data_encoding_ezjsonm.write_file filename json >>= function
|
2017-01-23 14:09:45 +04:00
|
|
|
| Error _ -> fail (Failure "Json.write_file")
|
|
|
|
| Ok () -> return ())
|
2016-09-08 21:13:10 +04:00
|
|
|
(fun exn ->
|
2016-12-03 16:05:02 +04:00
|
|
|
cctxt.Client_commands.error
|
|
|
|
"could not write the %s alias file: %s."
|
2016-09-08 21:13:10 +04:00
|
|
|
Entity.name (Printexc.to_string exn))
|
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let add cctxt name value =
|
2016-09-08 21:13:10 +04:00
|
|
|
let keep = ref false in
|
2016-12-03 16:05:02 +04:00
|
|
|
load cctxt >>= fun list ->
|
2017-03-15 04:17:20 +04:00
|
|
|
(if not cctxt.config.force then
|
2016-09-08 21:13:10 +04:00
|
|
|
Lwt_list.iter_s (fun (n, v) ->
|
|
|
|
if n = name && v = value then
|
2016-11-22 17:23:40 +04:00
|
|
|
(keep := true ;
|
2016-12-03 16:05:02 +04:00
|
|
|
cctxt.Client_commands.message
|
|
|
|
"The %s alias %s already exists with the same value." Entity.name n)
|
2016-09-08 21:13:10 +04:00
|
|
|
else if n = name && v <> value then
|
2016-12-03 16:05:02 +04:00
|
|
|
cctxt.Client_commands.error
|
|
|
|
"another %s is already aliased as %s, use -force true to update" Entity.name n
|
2016-09-08 21:13:10 +04:00
|
|
|
else if n <> name && v = value then
|
2016-12-03 16:05:02 +04:00
|
|
|
cctxt.Client_commands.error
|
|
|
|
"this %s is already aliased as %s, use -force true to insert duplicate" Entity.name n
|
2016-09-08 21:13:10 +04:00
|
|
|
else return ())
|
|
|
|
list else return ()) >>= fun () ->
|
|
|
|
let list = List.filter (fun (n, _) -> n <> name) list in
|
|
|
|
let list = (name, value) :: list in
|
|
|
|
if !keep then
|
|
|
|
return ()
|
|
|
|
else
|
2016-12-03 16:05:02 +04:00
|
|
|
save cctxt list >>= fun () ->
|
|
|
|
cctxt.Client_commands.message
|
|
|
|
"New %s alias '%s' saved." Entity.name name
|
2016-09-08 21:13:10 +04:00
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let del cctxt name =
|
|
|
|
load cctxt >>= fun list ->
|
2016-09-08 21:13:10 +04:00
|
|
|
let list = List.filter (fun (n, _) -> n <> name) list in
|
2016-12-03 16:05:02 +04:00
|
|
|
save cctxt list
|
2017-03-15 04:27:34 +04:00
|
|
|
|
|
|
|
let update cctxt name value =
|
|
|
|
load cctxt >>= fun list ->
|
|
|
|
let list =
|
|
|
|
List.map
|
|
|
|
(fun (n, v) -> (n, if n = name then value else v))
|
|
|
|
list in
|
|
|
|
save cctxt list
|
2016-09-08 21:13:10 +04:00
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let save cctxt list =
|
|
|
|
save cctxt list >>= fun () ->
|
|
|
|
cctxt.Client_commands.message
|
|
|
|
"Successful update of the %s alias file." Entity.name
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
include Entity
|
|
|
|
|
2016-12-05 16:18:12 +04:00
|
|
|
let alias_param ?(name = "name") ?(desc = "existing " ^ Entity.name ^ " alias") next =
|
2016-11-22 17:23:40 +04:00
|
|
|
param ~name ~desc
|
2016-12-03 16:05:02 +04:00
|
|
|
(fun cctxt s -> find cctxt s >>= fun v -> return (s, v))
|
2016-11-22 17:23:40 +04:00
|
|
|
next
|
|
|
|
|
2016-12-05 16:18:12 +04:00
|
|
|
let fresh_alias_param ?(name = "new") ?(desc = "new " ^ Entity.name ^ " alias") next =
|
2016-11-22 17:23:40 +04:00
|
|
|
param ~name ~desc
|
2016-12-03 16:05:02 +04:00
|
|
|
(fun cctxt s ->
|
|
|
|
load cctxt >>= fun list ->
|
2017-03-15 04:17:20 +04:00
|
|
|
if not cctxt.config.force then
|
2016-11-22 17:23:40 +04:00
|
|
|
Lwt_list.iter_s (fun (n, _v) ->
|
2016-12-05 16:18:12 +04:00
|
|
|
if n = s then
|
2016-12-03 16:05:02 +04:00
|
|
|
cctxt.Client_commands.error
|
|
|
|
"the %s alias %s already exists, use -force true to update" Entity.name n
|
2016-11-22 17:23:40 +04:00
|
|
|
else return ())
|
|
|
|
list >>= fun () ->
|
|
|
|
return s
|
|
|
|
else return s)
|
|
|
|
next
|
|
|
|
|
2016-12-05 16:18:12 +04:00
|
|
|
let source_param ?(name = "src") ?(desc = "source " ^ Entity.name) next =
|
2016-11-22 17:23:40 +04:00
|
|
|
let desc =
|
|
|
|
desc ^ "\n"
|
2016-11-22 20:33:17 +04:00
|
|
|
^ "can be an alias, file or literal (autodetected in this order)\n\
|
|
|
|
use 'file:path', 'text:literal' or 'alias:name' to force" in
|
2016-11-22 17:23:40 +04:00
|
|
|
param ~name ~desc
|
2016-12-03 16:05:02 +04:00
|
|
|
(fun cctxt s ->
|
2016-11-22 17:23:40 +04:00
|
|
|
let read path =
|
|
|
|
catch
|
|
|
|
(fun () -> Lwt_io.(with_file ~mode:Input path read))
|
|
|
|
(fun exn -> Lwt.fail_with @@ Format.asprintf "cannot read file (%s)" (Printexc.to_string exn))
|
2016-12-03 16:05:02 +04:00
|
|
|
>>= of_source cctxt in
|
2016-11-22 17:23:40 +04:00
|
|
|
match Utils.split ~limit:1 ':' s with
|
|
|
|
| [ "alias" ; alias ]->
|
2016-12-03 16:05:02 +04:00
|
|
|
find cctxt alias
|
2016-11-22 17:23:40 +04:00
|
|
|
| [ "text" ; text ] ->
|
2016-12-03 16:05:02 +04:00
|
|
|
of_source cctxt text
|
2016-11-22 17:23:40 +04:00
|
|
|
| [ "file" ; path ] ->
|
|
|
|
read path
|
|
|
|
| _ ->
|
|
|
|
catch
|
2016-12-03 16:05:02 +04:00
|
|
|
(fun () -> find cctxt s)
|
2016-11-22 17:23:40 +04:00
|
|
|
(fun _ ->
|
2016-09-08 21:13:10 +04:00
|
|
|
catch
|
2016-11-22 17:23:40 +04:00
|
|
|
(fun () -> read s)
|
2016-12-03 16:05:02 +04:00
|
|
|
(fun _ -> of_source cctxt s)))
|
2016-11-22 17:23:40 +04:00
|
|
|
next
|
2016-09-08 21:13:10 +04:00
|
|
|
|
2016-12-03 16:05:02 +04:00
|
|
|
let name cctxt d =
|
|
|
|
rev_find cctxt d >>= function
|
|
|
|
| None -> Entity.to_source cctxt d
|
2016-09-08 21:13:10 +04:00
|
|
|
| Some name -> Lwt.return name
|
|
|
|
|
|
|
|
end
|