Docs: add error documentation generation

This commit is contained in:
Vincent Botbol 2018-03-07 10:32:53 +01:00 committed by Benjamin Canou
parent 19eb1c2520
commit 385a600e98
6 changed files with 241 additions and 7 deletions

3
.gitignore vendored
View File

@ -21,6 +21,8 @@ __pycache__
/scripts/opam-test-all.sh.DONE
/docs/introduction/readme.rst
/docs/api/errors.rst
/docs/_extensions/*.pyc
*.install
.merlin
@ -30,4 +32,3 @@ __pycache__
*.rej
*.orig

View File

@ -5,18 +5,25 @@ SPHINXPROJ = Tezos
SOURCEDIR = .
BUILDDIR = _build
DOCGENDIR = doc_gen
DOCERRORDIR = $(DOCGENDIR)/errors
all: html linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck "$(SOURCEDIR)" "$(BUILDDIR)"
api/errors.rst: $(DOCERRORDIR)/error_doc.ml
@jbuilder build $(DOCERRORDIR)/error_doc.exe
../_build/default/docs/$(DOCERRORDIR)/error_doc.exe > api/errors.rst
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
html: Makefile
html: Makefile api/errors.rst
@$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
clean:
@-rm -Rf "$(BUILDDIR)"
@-rm -Rf introduction/readme.rst
@-rm -Rf introduction/readme.rst api/errors.rst

View File

@ -0,0 +1,204 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
(* Todo : add section descriptions *)
let default_section_id = "default"
let default_section_title = "Miscellaneous"
(* Association list where keys are set of identifier's prefixes that
maps to a section title. The ordering of sections in the rst output
depends on their position in this list.
e.g. : an error which id is 'utils.Timeout' will be documented
under the `Miscellaneous` section which will be displayed at the
bottom of the document. Unprefixed ids or unreferenced prefixes
will default to `Miscellaneous` *)
let section_titles =
[
[ "proto" ], "Protocol Alpha";
[ "baking" ], "Baking" ;
[ "contract" ], "Smart Contracts" ;
[ "distributed_db" ], "Database" ;
[ "micheline" ; "michelson" ], "Smart Contracts" ;
(* [ "michelson" ], "Michelson" ; *)
[ "node" ], "Client Node" ;
[ "operation" ], "Operations" ;
[ "prevalidation" ], "Prevalidation" ;
[ "raw_store" ], "Store" ;
[ "rpc_client" ], "RPC Client" ;
[ "tez" ], "Tezos operations" ;
[ "validator" ], "Validator" ;
[ "worker" ], "Worker" ;
(* [ "cli" ], "Command Line" ; *)
[ "cli"; "utils"; default_section_id ], default_section_title ;
]
let categories_detail =
[ "temporary", "An error resulting from an operation that might be \
valid in the future, for example, a contracts balance \
being too low to execute the intended operation. This \
can be fixed by adding more to the contracts balance."
; "branch", "An error that occurs in one branch of the chain, but may not \
occur in a different one. For example, receiving an \
operation for an old or future protocol version."
; "permanent", "An error that is not recoverable because the operation \
is never going to be valid. For example, an invalid \
notation." ]
let pp_rst_title ~char ppf title =
let sub = String.map (fun _ -> char) title in
Format.fprintf ppf "@[<v 0>%s@\n@]@[<v 0>%s@\n@\n@]" title sub
let pp_rst_h1 = pp_rst_title ~char:'#'
let pp_rst_h2 = pp_rst_title ~char:'*'
let pp_rst_h3 = pp_rst_title ~char:'='
let pp_rst_h4 = pp_rst_title ~char:'`'
let string_of_err_category =
let open Error_monad in function
| `Branch -> "branch"
| `Temporary -> "temporary"
| `Permanent -> "permanent"
let pp_info_to_rst
ppf
{ Error_monad.id ; title ; category ; description ; schema } =
let open Format in
fprintf ppf "@[<v 2>- **%s**@,@,"
(if title = "" then "<Untitled>" else title) ;
fprintf ppf "@[<v 0>%s@\n@\n@]"
(if description = "" then "Not description available" else description) ;
fprintf ppf "@[<v 0>* *Id* : %s@\n@\n@]" id ;
fprintf ppf "@[* *Category* : %s@\n@\n@]" (string_of_err_category category) ;
fprintf ppf "@[<v 2>.. container:: schema-button@\n@\n" ;
fprintf ppf "@[<v 2>Show schema@]@]@\n@\n" ;
fprintf ppf "@[<v 2>.. container:: schema@\n@\n" ;
fprintf ppf "@[<v 2>.. code-block:: json@\n@\n" ;
fprintf ppf "@[%a@]@]@]@]" Json_schema.pp schema
module ErrorSet = Set.Make(struct
type t = Error_monad.error_info
let compare { Error_monad.id ; _ } { Error_monad.id = id' ; _ } =
String.compare id id'
end)
module ErrorPartition = struct
include Map.Make(struct
include String
let titles = List.map snd section_titles
let compare s s' =
let idx s =
let rec loop acc = function
| [] -> assert false
| h::_ when h = s -> acc
| _::t -> loop (acc + 1) t
in loop 0 titles
in
Pervasives.compare (idx s) (idx s')
end)
let add_error (id : key) (error : Error_monad.error_info) (map : 'a t) =
let lr_opt = Stringext.cut id ~on:"." in
let id_prefix =
match lr_opt with
| None -> default_section_id
| Some (prefix, _r) -> prefix
in
let title =
try
snd (List.find
(fun (id_set, _) -> List.mem id_prefix id_set)
section_titles)
with
| Not_found -> default_section_title
in
let set =
try
find title map
with
| Not_found -> ErrorSet.empty
in
add title (ErrorSet.add error set) map
end
let pp_error_map ppf (map : ErrorSet.t ErrorPartition.t) : unit =
let open Format in
ErrorPartition.iter (fun section_title set ->
fprintf ppf "%a" pp_rst_h2 section_title ;
ErrorSet.iter
(fun error_repr ->
fprintf ppf "@[%a@]@\n@\n" pp_info_to_rst error_repr
) set
) map
let print_script ppf =
(* HACK : show/hide JSON schemas + style *)
Format.fprintf ppf "@[<v 2>.. raw:: html@\n@\n" ;
Format.fprintf ppf "@[<v 0>%s%s@]@\n@\n@]"
"<script>document.addEventListener('DOMContentLoaded', function(){\
$(\".schema-button\").click(function(){$(this).next(\".schema\")\
.first().toggle()})}, false);</script>"
"<style>.schema { display:none; margin:0 0 0 10px; }\
.schema-button { cursor:pointer; font-size:11px;\
font-weight: bold; background-color: #EEEEEE;\
color: #333333; padding: 2px 6px 2px 6px;\
border-top: 1px solid #CCCCCC; border-right: 1px solid #333333;\
border-bottom: 1px solid #333333; border-left: 1px solid #CCCCCC;\
width : -moz-fit-content; }\
section li { margin:10px 0 10px 0; } </style>"
(* Main *)
let () =
let open Format in
let ppf = std_formatter in
(* Header *)
let title = "Tezos Client Errors" in
fprintf ppf "%a" pp_rst_h1 title ;
print_script ppf ;
fprintf ppf "This document references possible errors.@\n@\n" ;
fprintf ppf "There are three categories of error :@\n@\n" ;
List.iter (fun (cat, descr) ->
fprintf ppf "- :literal:`%s` - %s@\n@\n" cat descr) categories_detail ;
fprintf ppf "See `The Error Monad`_ for further details.@\n@\n" ;
fprintf
ppf ".. _The Error Monad: \
../tutorials/error_monad.html#the-actual-tezos-error-monad@\n@\n" ;
(* Body *)
let map =
let all_errors =
Error_monad.get_registered_errors () in
List.fold_left
(fun acc ( Error_monad.{ id ; _ } as error ) ->
ErrorPartition.add_error id error acc
) ErrorPartition.empty all_errors
in
fprintf ppf "%a" pp_error_map map

View File

@ -0,0 +1,20 @@
(jbuild_version 1)
(executable
((name error_doc)
(libraries
(tezos-shell
tezos-embedded-protocol-alpha))
(flags (:standard -w -9+27-30-32-40@8
-open Tezos_base
-open Tezos_error_monad
-open Tezos_data_encoding
-open Tezos_embedded_protocol_alpha
-open Tezos_embedded_protocol_environment_alpha
-safe-string
-linkall))))
(alias
((name runtest_indent)
(deps ((glob_files *.ml*)))
(action (run bash ${libexec:tezos-stdlib:test-ocp-indent.sh} ${^}))))

View File

@ -83,6 +83,7 @@ license when the main network lunches.
README
api/api-inline
api/cli-commands
api/errors
Indices and tables
==================

View File

@ -19,6 +19,8 @@ type error += Cannot_freeze_endorsement_deposit (* `Permanent *)
type error += Inconsistent_endorsement of public_key_hash list (* `Permanent *)
type error += Empty_endorsement
type error += Invalid_block_signature of Block_hash.t * Ed25519.Public_key_hash.t (* `Permanent *)
type error += Invalid_signature (* `Permanent *)
type error += Invalid_stamp (* `Permanent *)
let () =
register_error_kind
@ -108,7 +110,9 @@ let () =
(req "block" Block_hash.encoding)
(req "expected" Ed25519.Public_key_hash.encoding))
(function Invalid_block_signature (block, pkh) -> Some (block, pkh) | _ -> None)
(fun (block, pkh) -> Invalid_block_signature (block, pkh))
(fun (block, pkh) -> Invalid_block_signature (block, pkh));
register_error_kind
`Permanent
~id:"baking.invalid_signature"
~title:"Invalid block signature"
~description:"The block's signature is invalid"
@ -251,9 +255,6 @@ let check_header_hash header stamp_threshold =
let hash = Block_header.hash header in
check_hash hash stamp_threshold
type error +=
| Invalid_stamp
let check_proof_of_work_stamp ctxt block =
let proof_of_work_threshold = Constants.proof_of_work_threshold ctxt in
if check_header_hash block proof_of_work_threshold then