1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# lv2docgen, a documentation generator for LV2 plugins
5# Copyright 2012 David Robillard <d@drobilla.net>
6#
7# Permission to use, copy, modify, and/or distribute this software for any
8# purpose with or without fee is hereby granted, provided that the above
9# copyright notice and this permission notice appear in all copies.
10#
11# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19import errno
20import os
21import sys
22
23__date__    = '2012-03-27'
24__version__ = '0.0.0'
25__authors__ = 'David Robillard'
26__license__ = 'ISC License <http://www.opensource.org/licenses/isc>'
27__contact__ = 'devel@lists.lv2plug.in'
28
29try:
30    import rdflib
31except ImportError:
32    sys.exit('Error importing rdflib')
33
34doap = rdflib.Namespace('http://usefulinc.com/ns/doap#')
35lv2  = rdflib.Namespace('http://lv2plug.in/ns/lv2core#')
36rdf  = rdflib.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
37rdfs = rdflib.Namespace('http://www.w3.org/2000/01/rdf-schema#')
38
39def uri_to_path(uri):
40    path = uri[uri.find(':'):]
41    while not path[0].isalpha():
42        path = path[1:]
43    return path
44
45def get_doc(model, subject):
46    comment = model.value(subject, rdfs.comment, None)
47    if comment:
48        return '<p class="content">%s</p>' % comment
49    return ''
50
51def port_doc(model, port):
52    name = model.value(port, lv2.name, None)
53    comment = model.value(port, rdfs.comment, None)
54    html = '<div class="specterm"><h3>%s</h3>' % name
55    html += get_doc(model, port)
56    html += '</div>'
57    return html
58
59def plugin_doc(model, plugin, style_uri):
60    uri  = str(plugin)
61    name = model.value(plugin, doap.name, None)
62
63    html = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
64<html about="%s"
65      xmlns="http://www.w3.org/1999/xhtml"
66      xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
67      xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
68      xmlns:lv2="http://lv2plug.in/ns/lv2core#"
69      xml:lang="en">''' % uri
70
71    html += '''<head>
72    <title>%s</title>
73    <meta http-equiv="content-type" content="text/xhtml+xml; charset=utf-8" />
74    <meta name="generator" content="lv2docgen" />
75    <link href="%s" rel="stylesheet" type="text/css" />
76  </head>
77  <body>''' % (name, style_uri)
78
79    html += '''
80  <!-- HEADER -->
81  <div id="header">
82    <h1 id="title">%s</h1>
83    <table id="meta">
84      <tr><th>URI</th><td><a href="%s">%s</a></td></tr>
85      <tr><th>Version</th><td>%s</td></tr>
86    </table>
87  </div>
88''' % (name, uri, uri, '0.0.0')
89
90    html += get_doc(model, plugin)
91
92    ports_html = ''
93    for p in model.triples([plugin, lv2.port, None]):
94        ports_html += port_doc(model, p[2])
95
96    if len(ports_html):
97        html += '''
98  <h2 class="sec">Ports</h2>
99  <div class="content">
100%s
101  </div>''' % ports_html
102
103    html += '  </body></html>'
104    return html
105
106if __name__ == '__main__':
107    'LV2 plugin documentation generator'
108
109    if len(sys.argv) < 2:
110        print('Usage: %s OUTDIR FILE...' % sys.argv[0])
111        sys.exit(1)
112
113    outdir = sys.argv[1]
114    files = sys.argv[2:]
115    model = rdflib.ConjunctiveGraph()
116    for f in files:
117        model.parse(f, format='n3')
118
119    style_uri = os.path.abspath(os.path.join(outdir, 'style.css'))
120    for p in model.triples([None, rdf.type, lv2.Plugin]):
121        plugin = p[0]
122        html = plugin_doc(model, plugin, style_uri)
123        path = uri_to_path(plugin)
124
125        outpath = os.path.join(outdir, path + '.html')
126        try:
127            os.makedirs(os.path.dirname(outpath))
128        except OSError:
129            e = sys.exc_info()[1]
130            if e.errno == errno.EEXIST:
131                pass
132            else:
133                raise
134
135            print('Writing <%s> documentation to %s' % (plugin, outpath))
136            out = open(outpath, 'w')
137            out.write(html)
138            out.close()
139