aboutsummaryrefslogtreecommitdiffstats
path: root/core.lv2/lv2config
blob: 6b22fd624f07b1c9d47691aed6dd52a0110c3d2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""A program (and Python module) to generate a tree of symlinks to LV2
extension bundles, where the path of the symlink corresponds to the URI of
the extension.  This allows including extension headers in code without using
the bundle name.  Including extension headers in this way is much better,
since there is no dependency on the (meaningless and non-persistent) bundle
name in the code using the header.

For example, after running lv2config (and setting the compiler include
path appropriately), LV2 headers could be included like so:

#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
#include "lv2/lv2plug.in/ns/ext/event/event.h"
#include "lv2/example.org/foo/foo.h"

Where the initial "lv2" is arbitrary; in this case lv2config's output
directory was "lv2", and that directory's parent was added to the compiler
include search path.  It is a good idea to use such a prefix directory so
domain names do not conflict with anything else in the include path.
"""

__authors__ = 'David Robillard'
__license   = 'GNU GPL v3 or later <http://www.gnu.org/licenses/gpl.html>'
__contact__ = 'devel@lists.lv2plug.in'
__date__    = '2010-10-05'

import errno
import glob
import os
import stat
import sys

redland = True

try:
    import RDF # Attempt to import Redland
except:
    try:
        import rdflib # Attempt to import RDFLib
        redland = False
    except:
        print >> sys.stderr, """Failed to import `RDF' (Redland) or `rdflib'.
(Please install either package, likely `python-librdf' or `python-rdflib')"""
        sys.exit(1)

def rdf_namespace(uri):
    "Create a new RDF namespace"
    if redland:
        return RDF.NS(uri)
    else:
        return rdflib.Namespace(uri)

def rdf_load(uri):
    "Load an RDF model"
    if redland:
        model = RDF.Model()
        parser = RDF.Parser(name="turtle")
        parser.parse_into_model(model, uri)
    else:
        model = rdflib.ConjunctiveGraph()
        model.parse(uri, format="n3")
    return model

def rdf_find_type(model, rdf_type):
    "Return a list of the URIs of all resources in model with a given type"
    if redland:
        results = model.find_statements(RDF.Statement(None, rdf.type, rdf_type))
        ret = []
        for r in results:
            ret.append(str(r.subject.uri))
        return ret
    else:
        results = model.triples([None, rdf.type, rdf_type])
        ret = []
        for r in results:
            ret.append(r[0])
        return ret

rdf = rdf_namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
lv2 = rdf_namespace('http://lv2plug.in/ns/lv2core#')

def lv2_path():
    "Return the LV2 search path (LV2_PATH in the environment, or a default)."
    if 'LV2_PATH' in os.environ:
        return os.environ['LV2_PATH']
    else:
        ret = '/usr/lib/lv2' + os.pathsep + '/usr/local/lib/lv2'
        print 'LV2_PATH unset, using default ' + ret
        return ret

def __bundles(search_path):
    "Return a list of all LV2 bundles found in search_path."
    dirs = search_path.split(os.pathsep)
    bundles = []
    for dir in dirs:
        bundles += glob.glob(os.path.join(dir, '*.lv2'))
    return bundles

def __mkdir_p(path):
    "Equivalent of UNIX mkdir -p"
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno == errno.EEXIST:
            pass
        else:
            raise

def build_tree(search_path, outdir):
    """Build a directory tree under outdir containing symlinks to all LV2
    extensions found in search_path, such that the symlink paths correspond to
    the extension URIs."""
    print "Building LV2 include tree at", outdir, "for", search_path
    if os.access(outdir, os.F_OK) and not os.access(outdir, os.W_OK):
        print >> sys.stderr, "lv2config: cannot build  `%s': Permission denied" % outdir
        sys.exit(1)
    for bundle in __bundles(search_path):
        # Load manifest into model
        manifest = rdf_load('file://' + os.path.join(bundle, 'manifest.ttl'))

        # Query extension URI
        specs = rdf_find_type(manifest, lv2.Specification)
        for ext_uri in specs:
            ext_scheme = ext_uri[0:ext_uri.find(':')] 
            ext_path   = os.path.normpath(ext_uri[ext_uri.find(':') + 1:].lstrip('/'))
            ext_dir    = os.path.join(outdir, ext_scheme, ext_path)

            # Make parent directories
            __mkdir_p(os.path.dirname(ext_dir))

            # Remove existing symlink if necessary
            if os.access(ext_dir, os.F_OK):
                mode = os.lstat(ext_dir)[stat.ST_MODE]
                if stat.S_ISLNK(mode):
                    os.remove(ext_dir)
                else:
                    raise Exception(ext_dir + " exists and is not a link")

            # Make symlink to bundle directory
            os.symlink(bundle, ext_dir)
            
def __usage():
    script = os.path.basename(sys.argv[0])
    print """Usage: %s
    Build the default system lv2 include directories,
    /usr/include/lv2 and /usr/local/include/lv2

Usage: %s INCLUDEDIR
    Build an lv2 include directory tree at INCLUDEDIR
    for all extensions found in $LV2_PATH.

Usage: %s BUNDLESDIR INCLUDEDIR
    Build an lv2 include directory tree at INCLUDEDIR
    for all extensions found in bundles under BUNDLESDIR.
""" % (script, script, script)

if __name__ == "__main__":
    args = sys.argv[1:]

    print args

    if len(args) == 0:
        build_tree('/usr/local/lib/lv2', '/usr/local/include/lv2')
        build_tree('/usr/lib/lv2',       '/usr/include/lv2')

    elif '--help' in args or '-h' in args:
        __usage()

    elif len(args) == 1:
        build_tree(lv2_path(), args[0])

    elif len(args) == 2:
        build_tree(args[0], args[1])
        
    else:
        __usage()
        sys.exit(1)