16480: Merge branch 'master'
[arvados.git] / doc / gen_api_method_docs.py
1 #! /usr/bin/env python
2 # Copyright (C) The Arvados Authors. All rights reserved.
3 #
4 # SPDX-License-Identifier: CC-BY-SA-3.0
5
6 # gen_api_method_docs.py
7 #
8 # Generate docs for Arvados methods.
9 #
10 # This script will retrieve the discovery document at
11 # https://localhost:9900/discovery/v1/apis/arvados/v1/rest
12 # and will generate Textile documentation files in the current
13 # directory.
14
15 import argparse
16 import pprint
17 import re
18 import requests
19 import os
20 import sys #debugging
21
22 p = argparse.ArgumentParser(description='Generate Arvados API method documentation.')
23
24 p.add_argument('--host',
25                type=str,
26                default='localhost',
27                help="The hostname or IP address of the API server")
28
29 p.add_argument('--port',
30                type=int,
31                default=9900,
32                help="The port of the API server")
33
34 p.add_argument('--output-dir',
35                type=str,
36                default='.',
37                help="Directory in which to write output files.")
38
39 args = p.parse_args()
40
41 api_url = 'https://{host}:{port}/discovery/v1/apis/arvados/v1/rest'.format(**vars(args))
42
43 r = requests.get(api_url, verify=False)
44 if r.status_code != 200:
45     raise Exception('Bad status code %d: %s' % (r.status_code, r.text))
46
47 if 'application/json' not in r.headers.get('content-type', ''):
48     raise Exception('Unexpected content type: %s: %s' %
49                     (r.headers.get('content-type', ''), r.text))
50
51 api = r.json()
52
53 resource_num = 0
54 for resource in sorted(api[u'resources']):
55     resource_num = resource_num + 1
56     out_fname = os.path.join(args.output_dir, resource + '.textile')
57     if os.path.exists(out_fname):
58         backup_name = out_fname + '.old'
59         try:
60             os.rename(out_fname, backup_name)
61         except OSError as e:
62             print "WARNING: could not back up {1} as {2}: {3}".format(
63                 out_fname, backup_name, e)
64     outf = open(out_fname, 'w')
65     outf.write(
66 """---
67 navsection: api
68 navmenu: API Methods
69 title: "{resource}"
70 navorder: {resource_num}
71 ---
72
73 h1. {resource}
74
75 Required arguments are displayed in %{{background:#ccffcc}}green%.
76
77 """.format(resource_num=resource_num, resource=resource))
78
79     methods = api['resources'][resource]['methods']
80     for method in sorted(methods.keys()):
81         methodinfo = methods[method]
82         outf.write(
83 """
84 h2. {method}
85
86 {description}
87
88 Arguments:
89
90 table(table table-bordered table-condensed).
91 |_. Argument |_. Type |_. Description |_. Location |_. Example |
92 """.format(
93     method=method, description=methodinfo['description']))
94
95         required = []
96         notrequired = []
97         for param, paraminfo in methodinfo['parameters'].iteritems():
98             paraminfo.setdefault(u'description', '')
99             paraminfo.setdefault(u'location', '')
100             limit = ''
101             if paraminfo.get('minimum', '') or paraminfo.get('maximum', ''):
102                 limit = "range {0}-{1}".format(
103                     paraminfo.get('minimum', ''),
104                     paraminfo.get('maximum', 'unlimited'))
105             if paraminfo.get('default', ''):
106                 if limit:
107                     limit = limit + '; '
108                 limit = limit + 'default %d' % paraminfo['default']
109             if limit:
110                 paraminfo['type'] = '{0} ({1})'.format(
111                     paraminfo['type'], limit)
112
113             row = "|{param}|{type}|{description}|{location}||\n".format(
114                 param=param, **paraminfo)
115             if paraminfo.get('required', False):
116                 required.append(row)
117             else:
118                 notrequired.append(row)
119
120         for row in sorted(required):
121             outf.write("{background:#ccffcc}." + row)
122         for row in sorted(notrequired):
123             outf.write(row)
124
125         # pprint.pprint(methodinfo)
126
127     outf.close()
128     print "wrote ", out_fname
129
130