]> xenbits.xensource.com Git - xcp/xen-api.git/commitdiff
Add lifecycle info and release notes to HTML API docs
authorRob Hoes <rob.hoes@citrix.com>
Tue, 25 May 2010 13:26:27 +0000 (14:26 +0100)
committerRob Hoes <rob.hoes@citrix.com>
Tue, 25 May 2010 13:26:27 +0000 (14:26 +0100)
Signed-off-by: Rob Hoes <rob.hoes@citrix.com>
ocaml/doc/OMakefile
ocaml/doc/apidoc.html
ocaml/doc/apidoc.js
ocaml/doc/jsapi.ml
ocaml/doc/style.css

index ef3359c587e273cf86c6a58ba51e123285da8ece..4c242157d36a213c7273bd2703afc3cc75abfc34 100644 (file)
@@ -4,6 +4,10 @@ OCamlLibrary(odoc_json, odoc_json)
 
 OCAML_LIBS += ../idl/datamodel
 OCAMLINCLUDES += ../idl
+
+CAMLP4_FILES = jsapi
+UseCamlp4(rpc-light.syntax, $(CAMLP4_FILES))
+
 OCamlProgram(jsapi, jsapi)
 
 .PHONY: doc
index c3ea31c1976426479abb5f5646aaa4c0a3d23b2c..ed8007770717a583452cdc886724c7f77c015713 100644 (file)
@@ -6,10 +6,13 @@
                <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
                <script type="text/javascript" src="main.js"></script>
                <script type="text/javascript" src="api/index.json"></script>
+               <script type="text/javascript" src="api/releases.json"></script>
                <script type="text/javascript" src="apidoc.js"></script>
                <script>
                        if (cls != "")
                                document.write('<script src="api/', cls, '.json" type="text/JavaScript"><\/script>');
+                       if (rel != "")
+                               document.write('<script src="api/', rel, '.json" type="text/JavaScript"><\/script>');
                </script>
                <link rel="stylesheet" href="style.css" />
        </head>
index 73473bd367b0f1ace5624dfa0950ed2c3ece514f..b3ed735e350ed296ef6aa8b7c026a4240b1bc654 100644 (file)
@@ -15,6 +15,7 @@
 // global variables
 
 var cls = getQuerystring('c');
+var rel = getQuerystring('r');
 
 function qualifier(q)
 {
@@ -74,6 +75,29 @@ function transform_default(t)
        return 'Unknown[' + t + ']';
 }
 
+function current_lifecycle_stage(s)
+{
+       if (s.length == 0)
+               return 'Prototype';
+       else {
+               last_transition = s[s.length-1][0];
+               switch (last_transition) {
+               case 'Deprecated':
+                       return 'Deprecated';
+                       break;
+               case 'Removed':
+                       return 'Removed';
+                       break;
+               case 'Published':
+               case 'Changed':
+               case 'Extended':
+               default:
+                       return '';
+                       break;
+               }
+       }
+}
+
 function make_field(fld, n)
 {
        name = fld.field_name;
@@ -81,20 +105,22 @@ function make_field(fld, n)
        html = "";      
        html = '<div class="field' + toggle(n) + '">';
        html += '<input type="button" class="small-button" value="details" onclick="showhide(document.getElementById(\'' + name + '_details\'))" />';
+       html += '<div class="lifecycle">' + current_lifecycle_stage(fld.lifecycle) + '</div>';
        html += '<div><span class="inline-type">' + transform_type(fld.ty) + '</span> <span class="field-name">' + name + '</span> <span class="inline-qualifier">[' + qualifier(fld.qualifier) + ']</span></div>';
        
        html += '<div  id="' + name + '_details" style="display: none">';
        html += '<div class="field-description">' + fld.field_description + '</div>';
        
        html += '<table class="field-table">';
-       if (fld.release != undefined) {
-               html += '<tr><td width="130px"><span class="field-head">Introduced in:</span></td><td>' + fld.release.internal[1] + '</td></tr>';
-               if (fld.release.internal_deprecated_since != undefined)
-                       html += '<tr><td width="130px"><span class="field-head">Deprecated since:</span></td><td>' + fld.release.internal_deprecated_since + '</td></tr>';
-       }
        if (fld.default_value != undefined)
                html += '<tr><td width="130px"><span class="field-head">Default value:</span></td><td>' + transform_default(fld.default_value) + '</td></tr>';
+       html += '</table>';
        
+       html += '<table class="field-table">';
+       for (i in fld.lifecycle) {
+               l = fld.lifecycle[i];
+               html += '<tr><td width="130px"><span class="field-head">' + l[0] + ' in:</span></td><td width="130px">' + l[1] + '</td><td>' + l[2] + '</td></tr>';
+       }
        html += '</table>';
        html += '</div></div>';
        
@@ -109,6 +135,7 @@ function make_message(msg, n)
        
        html += '<div class="field' + toggle(n) + '">';
        html += '<input type="button" class="small-button" value="details" onclick="showhide(document.getElementById(\'' + name + '_details\'))" />';
+       html += '<div class="lifecycle">' + current_lifecycle_stage(msg.msg_lifecycle) + '</div>';
        html += '<div><span class="inline-type">' + 
                (msg.msg_result != undefined ? transform_type(msg.msg_result[0]) : 'void') + 
                '</span> <span class="field-name">' + name + '</span> <span class="inline-params">(' +
@@ -142,10 +169,12 @@ function make_message(msg, n)
                }
                html += '</table></td></tr>';
        }
-       if (msg.msg_release != undefined) {
-               html += '<tr><td><span class="field-head">Introduced in:</span></td><td>' + msg.msg_release.internal[1] + '</td></tr>';
-               if (msg.msg_release.internal_deprecated_since != undefined)
-                       html += '<tr><td><span class="field-head">Deprecated since:</span></td><td>' + msg.msg_release.internal_deprecated_since + '</td></tr>';
+       html += '</table>';
+       
+       html += '<table class="field-table">';
+       for (i in msg.msg_lifecycle) {
+               l = msg.msg_lifecycle[i];
+               html += '<tr><td width="130px"><span class="field-head">' + l[0] + ' in:</span></td><td width="130px">' + l[1] + '</td><td>' + l[2] + '</td></tr>';
        }
        html += '</table>';
        
@@ -164,10 +193,21 @@ function class_doc()
        messages.sort(function(a, b){return a.msg_name.toLowerCase().charCodeAt(0) - b.msg_name.toLowerCase().charCodeAt(0)});
 
        html = "";
+       html += '<input type="button" class="small-button" value="details" onclick="showhide(document.getElementById(\'class_details\'))" />';
+       html += '<div class="lifecycle">' + current_lifecycle_stage(clsdoc.obj_lifecycle) + '</div>';
        html += '<h1 class="title">Class: ' + cls + '</h1>\n';
        
        html += '<div class="description">' + clsdoc.description + '</div>';
        
+       html += '<div  id="class_details" style="display: none">';
+       html += '<table class="field-table">';
+       for (i in clsdoc.obj_lifecycle) {
+               l = clsdoc.obj_lifecycle[i];
+               html += '<tr><td width="130px"><span class="field-head">' + l[0] + ' in:</span></td><td width="130px">' + l[1] + '</td><td>' + l[2] + '</td></tr>';
+       }
+       html += '</table>';
+       html += '</div>';
+       
        html += '<h2>Fields</h2>';
        if (fields.length > 0) {
                for (i in fields)
@@ -187,9 +227,60 @@ function class_doc()
        set_content(html);
 }
 
-function build()
+function compare_release_notes(a, b)
 {
+       function change_to_num(x) {
+               if (x.indexOf('Published') > -1) return '0';
+               else if (x.indexOf('Extended') > -1) return '1';
+               else if (x.indexOf('Changed') > -1) return '2';
+               else if (x.indexOf('Deprecated') > -1) return '3';
+               else if (x.indexOf('Removed') > -1) return '4';
+               else return '5';
+       }
+       function element_to_num(x) {
+               if (x.indexOf('object') > -1) return '0';
+               else if (x.indexOf('field') > -1) return '1';
+               else if (x.indexOf('message') > -1) return '2';
+               else return '3';
+       }
+       a = change_to_num(a[0]) + element_to_num(a[0]) + (a[1]+a[2]).toLowerCase();
+       b = change_to_num(b[0]) + element_to_num(b[0]) + (b[1]+b[2]).toLowerCase();
+       return a > b;
+}
+
+function release_doc()
+{      
+       changes = [];
+       
+       for (i in release_info) {
+               c = release_info[i];
+               for (j in c.obj_changes)
+                       changes.push([c.obj_changes[j][0] + ' object', c.cls, '', c.obj_changes[j][2]]);
+               for (j in c.field_changes)
+                       changes.push([c.field_changes[j][0] + ' field', c.cls, c.field_changes[j][1], c.field_changes[j][2]]);
+               for (j in c.msg_changes)
+                       changes.push([c.msg_changes[j][0] + ' message', c.cls, c.msg_changes[j][1], c.msg_changes[j][2]]);
+       }
+       
+       changes.sort(compare_release_notes);
+       
        html = "";
+       html += '<h1 class="title">Release notes: ' + rel + '</h1>\n';
+
+       html += '<table><tr><th style="width: 12em">Change</th><th>Element</th><th>Description</th></tr>';
+               
+       for (i in changes) {
+               html += '<tr><td>' + changes[i][0] + '</td><td><a href="?c=' + changes[i][1] + (changes[i][2] != '' ? '#' + changes[i][2] : '') + '">' +
+                       changes[i][1] + (changes[i][2] != '' ? '.' + changes[i][2] : '') + '</a></td><td>' + changes[i][3] + '</td></tr>';
+       }
+       
+       html += '</table>';
+
+       set_content(html);
+}
+
+function class_list()
+{
        html = '<h2 class="title">Classes</h2>';
        
        classes.sort(function(a, b){return a.toLowerCase().charCodeAt(0) - b.toLowerCase().charCodeAt(0)});
@@ -199,9 +290,35 @@ function build()
        }
        
        append_sidebar(html);
+}
+
+function release_list()
+{
+       html = '<h2>Release notes</h2>';
+       
+       for (i in releases) {
+               r = releases[i];
+               html += '<a href="?r=' + r + '">' + r + '</a><br>';
+       }
        
+       append_sidebar(html);
+}
+
+function build()
+{
        if (cls != "") {
+               class_list();
+               release_list();
                class_doc();
        }
+       else if (rel != "") {
+               class_list();
+               release_list();
+               release_doc();
+       }
+       else {
+               class_list();
+               release_list();
+       }
 }
 
index ad1c4f5e492e0e206bf69d7bf1823b2339163579..7ebb8c962b0fad9f9899a4b2fc4757e3579ee784 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Lesser General Public License for more details.
  *)
+open Datamodel_types
+open Stringext
 
+type change_t = lifecycle_change * string * string
+and changes_t = change_t list
+with rpc
+
+let obj_change_in_release rel o =
+       let rec find_rel rel = function
+               | [] -> None
+               | (transition, release, doc) :: tl when release = rel -> Some (transition, o.name, doc)
+               | _ :: tl -> find_rel rel tl
+       in
+       find_rel rel o.obj_lifecycle
+       
+let msg_change_in_release rel m =
+       let rec find_rel rel = function
+               | [] -> None
+               | (transition, release, doc) :: tl when release = rel -> Some (transition, m.msg_name, doc)
+               | _ :: tl -> find_rel rel tl
+       in
+       find_rel rel m.msg_lifecycle
+
+let field_change_in_release rel f =
+       let rec find_rel rel = function
+               | [] -> None
+               | (transition, release, doc) :: tl when release = rel -> Some (transition, f.field_name, doc)
+               | _ :: tl -> find_rel rel tl
+       in
+       find_rel rel f.lifecycle
+       
 let _ =
-       let api = (* Datamodel_utils.add_implicit_messages *) (Datamodel.all_api) in
+       let api = (Datamodel.all_api) in
        let objs = Dm_api.objects_of_api api in
        let create_json obj =
-               let name = obj.Datamodel_types.name in
-               let s = Jsonrpc.to_string (Datamodel_types.rpc_of_obj obj) in
+               let name = obj.name in
+               let s = Jsonrpc.to_string (rpc_of_obj obj) in
                Unixext.write_string_to_file ("api/" ^ name ^ ".json") ("clsdoc = " ^ s);
                name
        in
        let names = List.map create_json objs in
        let class_list = String.concat ", " (List.map (fun s -> "'" ^ s ^ "'") names) in
-       Unixext.write_string_to_file "api/index.json" ("classes = [" ^ class_list ^ "]")
+       Unixext.write_string_to_file "api/index.json" ("classes = [" ^ class_list ^ "]");
        
+       let new_in_release rel =
+               let search_obj obj =
+                       let obj_changes : changes_t = 
+                               match obj_change_in_release rel obj with
+                               | None -> []
+                               | Some x -> [x]
+                       in
+                               
+                       let msgs = List.filter (fun m -> not m.msg_hide_from_docs) obj.messages in
+                       let msg_changes : changes_t = List.fold_left
+                               (fun l m -> match msg_change_in_release rel m with None -> l | Some x -> x :: l) [] msgs in
+                               
+                       let flds = List.filter (function Field f -> true | _ -> false) obj.contents in
+                       let field_changes : changes_t = List.fold_left
+                               (fun l (Field f) -> match field_change_in_release rel f with None -> l | Some x -> x :: l) [] flds in
+                               
+                       "{'cls': '" ^ obj.name ^ "', 'obj_changes': " ^ Jsonrpc.to_string (rpc_of_changes_t obj_changes) ^ ", 'field_changes': " ^ Jsonrpc.to_string (rpc_of_changes_t field_changes) ^ ", 'msg_changes': " ^ Jsonrpc.to_string (rpc_of_changes_t msg_changes) ^ "}"
+               in
+               let release_info = String.concat ", " (List.map search_obj objs) in
+               Unixext.write_string_to_file ("api/" ^ rel ^ ".json") ("release_info = [" ^ release_info ^ "]")
+       in
+       List.iter new_in_release release_order;
+       let release_list = String.concat ", " (List.map (fun s -> "'" ^ s ^ "'") release_order) in
+       Unixext.write_string_to_file "api/releases.json" ("releases = [" ^ release_list ^ "]");
index fc110407760b5da83dd126e13b6810c49f9a68c6..49479014298dd8897d2cb2592e525273c2c045cb 100644 (file)
@@ -188,7 +188,7 @@ table
 
 td {
        vertical-align: top;
-       padding: 3px;
+       padding: 3px 1em 3px 0;
 }
 
 th {
@@ -274,11 +274,18 @@ tt, .code {
        margin-left: .5em;
 }
 
+.lifecycle {
+       font-size: 90%;
+       float: right;
+       font-variant:small-caps;
+       color: #900;
+       margin: auto 0.5em;
+}
+
 .small-button {
        font-size: 70%;
-//     text-align: right;
        float: right;
-       margin: .5em 0;
+       margin: 0.2em 0 0.2em 0.5em;
 }
 
 .stat {