createdoc.py
changeset 302 3f4bdea2abbf
parent 294 0e75bd39767d
child 312 42fd5075a5d1
equal deleted inserted replaced
90:eb04ac3a8327 302:3f4bdea2abbf
     1 #!/usr/bin/env python2.7
     1 #!/usr/bin/env python2.7
       
     2 
       
     3 # Copyright (c) 2012 netzguerilla.net <iro@netzguerilla.net>
       
     4 # 
       
     5 # This file is part of Iro.
       
     6 # 
       
     7 # Permission is hereby granted, free of charge, to any person obtaining a copy of
       
     8 # this software and associated documentation files (the "Software"), to deal in
       
     9 # the Software without restriction, including without limitation the rights to use,
       
    10 # copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
       
    11 # #Software, and to permit persons to whom the Software is furnished to do so,
       
    12 # subject to the following conditions:
       
    13 # 
       
    14 # The above copyright notice and this permission notice shall be included in
       
    15 # all copies or substantial portions of the Software.
       
    16 # 
       
    17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       
    18 # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       
    19 # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       
    20 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       
    21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       
    22 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
    23 
     2 # -*- coding: utf-8 -*- 
    24 # -*- coding: utf-8 -*- 
     3 
    25 
     4 from genshi.template import TemplateLoader
    26 from genshi.template import TemplateLoader
     5 
    27 from genshi import Markup
     6 loader = TemplateLoader('doc/tmpl', auto_reload=True)
    28 loader = TemplateLoader('doc/tmpl', auto_reload=True)
     7 
    29 
       
    30 
       
    31 from glob import glob
     8 import re
    32 import re
       
    33 import os.path
     9 import inspect
    34 import inspect
    10 from iro.user import User as Current
    35 from pkg_resources import parse_version
    11 from iro.newuser import User as New
    36 
       
    37 from docutils.core import publish_doctree, publish_from_doctree, publish_string
       
    38 from docutils.utils import new_document
       
    39 from docutils.writers.html4css1 import Writer,HTMLTranslator
       
    40 
       
    41 from iro.view.xmlrpc import TwistedInterface as Current 
       
    42 from iro import __version__
       
    43 from createerm import createSchemaPlot, tables, tables_cls
       
    44 
       
    45 #redering text with rest syntax
       
    46 class NoHeaderHTMLTranslator(HTMLTranslator):
       
    47     def __init__(self, document):
       
    48         HTMLTranslator.__init__(self,document)
       
    49         self.body_prefix = []
       
    50         self.body_suffix = []
       
    51 
       
    52 _w = Writer()
       
    53 _w.translator_class = NoHeaderHTMLTranslator
       
    54 _w.visitor_attributes = ("html_body",)
       
    55 
       
    56 def d():
       
    57     subs = _w.interpolation_dict()
       
    58     return "%(html_body)s"%subs
       
    59 
       
    60 _w.apply_template = d
       
    61 
       
    62 def reSTify(s):
       
    63     d = new_document("")
       
    64     if s.tagname == "paragraph":
       
    65         d.append(s[0])
       
    66     else:
       
    67         d.append(s)
       
    68 
       
    69     return publish_from_doctree(d, writer=_w)
       
    70 
    12 
    71 
    13 
    72 
    14 
    73 
    15 class Link():
    74 class Link():
    16     def __init__(self,name,title):
    75     def __init__(self,name,title):
    28 class Site(Link):
    87 class Site(Link):
    29     pass
    88     pass
    30 
    89 
    31 
    90 
    32 class Keyword():
    91 class Keyword():
    33     def __init__(self,name,typ,description):
    92     def __init__(self, name=None, typ=None, description=None):
    34         self.name=name
    93         self.name=name
    35         self.typ=typ
    94         self.typ=typ
    36         self.description=description
    95         self.description=description
    37 
    96 
    38 def section(text):
    97     def __repr__(self):
    39     ret={}
    98         return '<Keyword("%s", "%s", "%s")>'%(self.name, self.typ, self.description)
    40     li=[]
    99 
    41     kw=None
   100 def keywords(f):
    42     for line in text.split("\n"):
   101     NORMAL = 0
    43         if re.match("^\s*$",line):
   102     TYPE = 1
    44             continue
   103     pd = publish_doctree(f.__doc__.decode('utf8'))
    45 
   104 
    46         if line[0] not in (" ","\t"):
   105     kws={}
    47             if kw:
   106     for child in pd[1][0]:
    48                 ret[kw.name]=kw
   107         kw = Keyword()
    49                 li.append(kw)
   108         ftyp = NORMAL
    50             l=re.match(r"^(?P<name>[a-zA-Z0-9-_.]*)\[(?P<typ>[a-zA-Z0-9-_|]*)\]:(?P<d>.*)$",line)
   109         for sc in child:
    51             kw=Keyword(name=l.group("name"),typ=l.group("typ"),description=l.group("d"))
   110             if sc.tagname == "field_name":
       
   111                 p = sc.astext().split()
       
   112                 if p[0] in ["param",]:
       
   113                     if len(p) == 3:             #param typ name
       
   114                         kw.name = p[2]
       
   115                         kw.typ = p[1]
       
   116                     if len(p) == 2:
       
   117                         kw.name = p[1]
       
   118                 elif p[0] == "type":
       
   119                     kw = kws[p[1]]
       
   120                     ftyp=TYPE
       
   121                 elif p[0] in ["return","rtyp"]:
       
   122                     break
       
   123                 else:
       
   124                     raise Exception("Unknown field_name: %s"%(p[0]))
       
   125             if sc.tagname == "field_body":
       
   126                 if ftyp == NORMAL:
       
   127                     kw.description = Markup(reSTify(sc[0]))
       
   128                 if ftyp == TYPE:
       
   129                     kw.typ = sc[0][0]
    52         else:
   130         else:
    53             kw.description+="\n"+line.strip()
   131             kws[kw.name] = kw
    54     if kw:
   132     return kws
    55         ret[kw.name]=kw
       
    56         li.append(kw)
       
    57     return ret,li
       
    58 
       
    59 
       
    60 
       
    61 def keywords(f):
       
    62     doc=f.__doc__
       
    63     kwds=re.search("Keywords:\n(?P<keywords>(?P<whitespace>\s*)(.+\n)*)\n",doc)
       
    64     k=kwds.group("keywords")
       
    65     #get rid of beginning whitespaces
       
    66     k=re.sub(re.compile(r"^"+kwds.group("whitespace"),re.M),"",k)
       
    67     return section(k)
       
    68 
   133 
    69 def ret(f):
   134 def ret(f):
    70     doc=f.__doc__
   135     NORMAL = 0
    71     kwds=re.search("Return:\n(?P<ret>(?P<whitespace>\s*)(.+\n)*)\n",doc)
   136     TYPE = 1
    72     k=kwds.group("ret")
   137     
    73     #get rid of beginning whitespaces
   138     pd = publish_doctree(f.__doc__.decode('utf8'))
    74     k=re.sub(re.compile(r"^"+kwds.group("whitespace"),re.M),"",k)
   139     for child in pd[1][0]:
    75     return section(k)
   140         kw = Keyword(name="return")
    76 
   141         ftyp = NORMAL
    77 
   142         for sc in child:
    78 
   143             if sc.tagname == "field_name":
       
   144                 p = sc.astext().split()
       
   145                 if p[0] == "return":
       
   146                     if len(p) == 2:
       
   147                         kw.typ = p[1]
       
   148                 elif p[0] == "rtype":
       
   149                     ftyp=TYPE
       
   150                 elif p[0] in ["param","type"]:
       
   151                     break
       
   152                 else:
       
   153                     raise Exception("Unknown field_name: %s"%(p[0]))
       
   154             if sc.tagname == "field_body":
       
   155                 if ftyp == NORMAL:
       
   156                     kw.description = Markup(reSTify(sc[0]))
       
   157                 if ftyp == TYPE:
       
   158                     kw.typ = sc[0][0]
       
   159         else:
       
   160             return kw
       
   161     
       
   162     raise Exception("no return description")
       
   163  
    79 class Arg():
   164 class Arg():
    80     def __init__(self,name,f):
   165     def __init__(self,name,f):
    81         self.name=name
   166         self.name=name
    82         k,_ = keywords(f)
   167         k = keywords(f)
    83         kwd=k[name]
   168         kwd=k[name]
    84         self.typ=kwd.typ
   169         self.typ=kwd.typ
    85         self.description=kwd.description
   170         self.description=kwd.description
    86 
       
    87         
       
    88 
   171 
    89 class Method(Link):
   172 class Method(Link):
    90     def __init__(self,name,methods):
   173     def __init__(self,name,methods):
    91         title=name[0].upper()+name[1:]
   174         title=name[0].upper()+name[1:]
    92         Link.__init__(self,name,title)
   175         Link.__init__(self,name,title)
    93         m=methods[name]
   176         m=methods[name]
    94         (args, varargs, keywords, defaults)=inspect.getargspec(m)
   177         (args, varargs, keywords, defaults)=inspect.getargspec(m)
    95         args= [b for b in args if b is not "self"]
   178         a=[]
       
   179         for b in args:
       
   180             if b in ("self","session"):
       
   181                 continue
       
   182             else:
       
   183                 a.append(b)
       
   184         
       
   185         args = a
    96         self.func_line=inspect.formatargspec(args, varargs, keywords, defaults)
   186         self.func_line=inspect.formatargspec(args, varargs, keywords, defaults)
    97         self.description = m.__doc__.split("\n")[0]
   187         pd = publish_doctree(m.__doc__)
       
   188         if pd[0].tagname == "paragraph":
       
   189             self.description = pd[0].astext()
    98         self.args=[Arg(a,m) for a in args]
   190         self.args=[Arg(a,m) for a in args]
    99         _, self.rets=ret(m)
   191         self.rets=[ret(m)]
       
   192 
       
   193 class Table(Link):
       
   194     def __init__(self,cls):
       
   195         name=cls.__name__
       
   196         self.tablename=cls.__tablename__
       
   197         title=self.tablename[0].upper()+self.tablename[1:]
       
   198         Link.__init__(self,name,title)
       
   199         
       
   200         self.description = Markup(publish_string(cls.__doc__,writer=_w))
       
   201 
       
   202 class File:
       
   203     def __init__(self,path):
       
   204         self.version = re.search("/iro-(.*).tar.gz",path).group(1)
       
   205         self.name = os.path.basename(path)
   100 
   206 
   101 
   207 
   102 def main():
   208 def main():
   103     sites=[Site("index.html","Iro"),
   209     sites=[Site("index.html","Iro"),
   104            Site("current.html","API Documentation"),
   210            Site("current.html","API Documentation"),
   105            Site("new.html","geplante API Documentation"),
   211            Site("database.html","Datenbase Schema"),
   106            Site("impressum.html","Impressum"),
   212            Site("about.html","About us"),
   107            ]
   213            ]
   108 
   214 
   109     current_methods = dict(inspect.getmembers(Current(None,None)))
   215     files=[File(f) for f in glob("web/files/*tar.gz")]
   110     current=[
   216     files.sort(key=lambda a:parse_version(a.version),reverse=True)
   111             Method("startSMS",current_methods),
   217     code ="files/iro-%s.tar.gz"%__version__
   112             Method("startFAX",current_methods),
   218 
   113             Method("startMail",current_methods),
   219     current_methods = dict(inspect.getmembers(Current()))
   114             
   220     current=[ Method(i,current_methods) for i in Current().listMethods() if i  != "listMethods" ]
   115             Method("status",current_methods),
   221     
   116             Method("stop",current_methods),
   222     t = [Table(tables_cls[str(f)]) for f in tables]
   117             
   223     createSchemaPlot('web/images/db-schema.svg')
   118             Method("getProvider",current_methods),
   224 
   119             Method("getDefaultProvider",current_methods),
   225     gd = {"sites":sites,
   120             ]
   226           "current":current,
   121 
   227           "tables": t,
   122     new_methods = dict(inspect.getmembers(New()))
   228           "code":code,
   123     newm=[
   229           "files":files
   124             Method("sms",new_methods),
   230         }
   125             Method("fax",new_methods),
       
   126             Method("mail",new_methods),
       
   127             
       
   128             Method("status",new_methods),
       
   129             Method("stop",new_methods),
       
   130             
       
   131             Method("routes",new_methods),
       
   132             Method("defaultRoute",new_methods),
       
   133             ]
       
   134 
       
   135 
   231 
   136     for site in sites:
   232     for site in sites:
   137         print("generiere %s" % site.name)
   233         print("generiere %s" % site.name)
   138         tmpl = loader.load(site.name)
   234         tmpl = loader.load(site.name)
   139         def a(s):
   235         def a(s):
   140             if s == site:
   236             if s == site:
   141                 return {"class":"menu active"}
   237                 return {"class":"menu active"}
   142         stream = tmpl.generate(sites=sites,active=a,current=current,new=newm)
   238         stream = tmpl.generate(active=a, **gd)
   143         with open('doc/'+site.name, "w") as g:
   239         with open('web/'+site.name, "w") as g:
   144             g.write(stream.render('html', doctype='html'))
   240             g.write(stream.render('html', doctype='html'))
   145 
   241 
   146 if __name__ == '__main__':
   242 if __name__ == '__main__':
   147     main()
   243     main()