#!/usr/bin/python # -*- coding: utf-8 -*- ################################################################################ ### @brief creates swagger json files from doc headers of rest files ### ### find files in ### arangod/RestHandler/*.cpp ### js/actions/api-*.js ### ### @usage generateSwagger.py < RestXXXX.cpp > restSwagger.json ### ### @file ### ### DISCLAIMER ### ### Copyright 2004-2014 triAGENS GmbH, Cologne, Germany ### ### Licensed under the Apache License, Version 2.0 (the "License"); ### you may not use this file except in compliance with the License. ### You may obtain a copy of the License at ### ### http://www.apache.org/licenses/LICENSE-2.0 ### ### Unless required by applicable law or agreed to in writing, software ### distributed under the License is distributed on an "AS IS" BASIS, ### WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ### See the License for the specific language governing permissions and ### limitations under the License. ### ### Copyright holder is triAGENS GmbH, Cologne, Germany ### ### @author Dr. Frank Celler ### @author Thomas Richter ### @author Copyright 2014, triAGENS GmbH, Cologne, Germany ################################################################################ import sys, re, json, string, os rc = re.compile MS = re.M | re.S ################################################################################ ### @brief swagger ################################################################################ swagger = { 'apiVersion': '0.1', 'swaggerVersion': '1.1', 'basePath': '/', 'apis': [] } ################################################################################ ### @brief operation ################################################################################ operation = {} ################################################################################ ### @brief C_FILE ################################################################################ C_FILE = False ################################################################################ ### @brief DEBUG ################################################################################ DEBUG = False ################################################################################ ### @brief trim_text ################################################################################ def trim_text(txt): r = rc(r"""[ \t]+$""") txt = r.sub("", txt) return txt ################################################################################ ### @brief parameters ### ### suche die erste { ### suche die letzten } ### gib alles dazwischen zurck ################################################################################ def parameters(line): (l, c, line) = line.partition('{') (line, c , r) = line.rpartition('}') line = BackTicks(line, wordboundary = ['{','}']) return line ################################################################################ ### @brief BackTicks ### ### `word` -> word ################################################################################ def BackTicks(txt, wordboundary = ['','']): r = rc(r"""([\(\s'/">]|^|.)\`(.*?)\`([<\s\.\),:;'"?!/-]|$)""", MS) subpattern = '\\1' + wordboundary[0] + '\\2' + wordboundary[1] + '\\3' return r.sub(subpattern, txt) ################################################################################ ### @brief AsteriskItalic ### ### *word* -> word ################################################################################ def AsteriskItalic(txt, wordboundary = ['','']): r = rc(r"""([\(\s'/">]|^|.)\*(.*?)\*([<\s\.\),:;'"?!/-]|$)""", MS) subpattern = '\\1' + wordboundary[0] + '\\2' + wordboundary[1] + '\\3' return r.sub(subpattern, txt) ################################################################################ ### @brief AsteriskBold ### ### **word** -> word ################################################################################ def AsteriskBold(txt, wordboundary = ['','']): r = rc(r"""([\(\s'/">]|^|.)\*\*(.*?)\*\*([<\s\.\),:;'"?!/-]|$)""", MS) subpattern = '\\1' + wordboundary[0] + '\\2' + wordboundary[1] + '\\3' return r.sub(subpattern, txt) ################################################################################ ### @brief FA ### ### @FA{word} -> word ################################################################################ def FA(txt, wordboundary = ['','']): r = rc(r"""([\(\s'/">]|^|.)@FA\{(.*?)\}([<\s\.\),:;'"?!/-]|$)""", MS) subpattern = '\\1' + wordboundary[0] + '\\2' + wordboundary[1] + '\\3' return r.sub(subpattern, txt) ################################################################################ ### @brief FN ### ### @FN{word} -> word ################################################################################ def FN(txt, wordboundary = ['','']): r = rc(r"""([\(\s'/">]|^|.)@FN\{(.*?)\}([<\s\.\),:;'"?!/-])""", MS) subpattern = '\\1' + wordboundary[0] + '\\2' + wordboundary[1] + '\\3' return r.sub(subpattern, txt) ################################################################################ ### @brief LIT ### ### @LIT{word} -> word ################################################################################ def LIT(txt, wordboundary = ['','']): r = rc(r"""([\(\s'/">]|^)@LIT\{(.*?)\}([<\s\.\),:;'"?!/-])""", MS) subpattern = '\\1' + wordboundary[0] + '\\2' + wordboundary[1] + '\\3' return r.sub(subpattern, txt) ################################################################################ ### @brief Typegraphy ################################################################################ def Typography(txt): if C_FILE: txt = txt[4:-1] else: txt = txt[0:-1] txt = BackTicks(txt) txt = AsteriskBold(txt) txt = AsteriskItalic(txt) txt = FN(txt) txt = LIT(txt) txt = FA(txt) # no way to find out the correct link for Swagger, # so replace all @ref elements with just "the manual" r = rc(r"""@ref [a-zA-Z0-9]+""", MS) txt = r.sub("the manual", txt) txt = re.sub(r"@endDocuBlock", "", txt) return txt ################################################################################ ### @brief InitializationError ################################################################################ class InitializationError(Exception): pass ################################################################################ ### @brief StateMachine ################################################################################ class StateMachine: def __init__(self): self.handlers = [] self.startState = None self.endStates = [] def add_state(self, handler, end_state=0): self.handlers.append(handler) if end_state: self.endStates.append(handler) def set_start(self, handler): self.startState = handler def run(self, cargo=None): if not self.startState: raise InitializationError,\ "must call .set_start() before .run()" if not self.endStates: raise InitializationError, \ "at least one state must be an end_state" handler = self.startState while 1: (newState, cargo) = handler(cargo) if newState in self.endStates: newState(cargo) break elif newState not in self.handlers: raise RuntimeError, "Invalid target %s" % newState else: handler = newState ################################################################################ ### @brief Regexen ################################################################################ class Regexen: def __init__(self): self.DESCRIPTION_LI = re.compile('^-\s.*$') self.DESCRIPTION_SP = re.compile('^\s\s.*$') self.DESCRIPTION_BL = re.compile('^\s*$') self.EMPTY_LINE = re.compile('^\s*$') self.END_EXAMPLE_ARANGOSH_RUN = re.compile('.*@END_EXAMPLE_ARANGOSH_RUN') self.EXAMPLES = re.compile('.*@EXAMPLES') self.EXAMPLE_ARANGOSH_RUN = re.compile('.*@EXAMPLE_ARANGOSH_RUN{') self.FILE = re.compile('.*@file') self.RESTBODYPARAM = re.compile('.*@RESTBODYPARAM') self.RESTDESCRIPTION = re.compile('.*@RESTDESCRIPTION') self.RESTDONE = re.compile('.*@RESTDONE') self.RESTHEADER = re.compile('.*@RESTHEADER{') self.RESTHEADERPARAM = re.compile('.*@RESTHEADERPARAM{') self.RESTHEADERPARAMETERS = re.compile('.*@RESTHEADERPARAMETERS') self.RESTQUERYPARAM = re.compile('.*@RESTQUERYPARAM{') self.RESTQUERYPARAMETERS = re.compile('.*@RESTQUERYPARAMETERS') self.RESTRETURNCODE = re.compile('.*@RESTRETURNCODE{') self.RESTRETURNCODES = re.compile('.*@RESTRETURNCODES') self.RESTURLPARAM = re.compile('.*@RESTURLPARAM{') self.RESTURLPARAMETERS = re.compile('.*@RESTURLPARAMETERS') self.NON_COMMENT = re.compile('^[^/].*') ################################################################################ ### @brief checks for end of comment ################################################################################ def check_end_of_comment(line, r): if C_FILE: return r.NON_COMMENT.match(line) else: return r.RESTDONE.match(line) ################################################################################ ### @brief next_step ################################################################################ def next_step(fp, line, r): global operation if not line: return eof, (fp, line) elif check_end_of_comment(line, r): return skip_code, (fp, line) elif r.EXAMPLE_ARANGOSH_RUN.match(line): return example_arangosh_run, (fp, line) elif r.RESTBODYPARAM.match(line): return restbodyparam, (fp, line) elif r.RESTDESCRIPTION.match(line): return restdescription, (fp, line) elif r.RESTHEADER.match(line): return restheader, (fp, line) elif r.RESTHEADERPARAM.match(line): return restheaderparam, (fp, line) elif r.RESTHEADERPARAMETERS.match(line): return restheaderparameters, (fp, line) elif r.RESTQUERYPARAM.match(line): return restqueryparam, (fp, line) elif r.RESTQUERYPARAMETERS.match(line): return restqueryparameters, (fp, line) elif r.RESTRETURNCODE.match(line): return restreturncode, (fp, line) elif r.RESTRETURNCODES.match(line): return restreturncodes, (fp, line) elif r.RESTURLPARAM.match(line): return resturlparam, (fp, line) elif r.RESTURLPARAMETERS.match(line): return resturlparameters, (fp, line) if r.EXAMPLES.match(line): operation['examples'] = "" return examples, (fp, line) return None, None ################################################################################ ### @brief generic handler ################################################################################ def generic_handler(cargo, r, message): global DEBUG if DEBUG: print >> sys.stderr, message (fp, last) = cargo while 1: (next, c) = next_step(fp, fp.readline(), r) if next: return next, c ################################################################################ ### @brief generic handler with description ################################################################################ def generic_handler_desc(cargo, r, message, op, para, name): global DEBUG, C_FILE, operation if DEBUG: print >> sys.stderr, message (fp, last) = cargo inLI = False inUL = False while 1: line = fp.readline() (next, c) = next_step(fp, line, r) if next: para[name] = trim_text(para[name]) if op: operation[op].append(para) return next, c if C_FILE and line[0:4] == "////": continue line = Typography(line) if r.DESCRIPTION_LI.match(line): line = "
'
for line in examplefile.readlines():
operation['examples'] += line
operation['examples'] += '