1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""
5Backend management.
6
7
8Creating new backends
9---------------------
10
11A new backend named 'foo-bar' corresponds to Python module
12'tracetool/backend/foo_bar.py'.
13
14A backend module should provide a docstring, whose first non-empty line will be
15considered its short description.
16
17All backends must generate their contents through the 'tracetool.out' routine.
18
19
20Backend attributes
21------------------
22
23========= ====================================================================
24Attribute Description
25========= ====================================================================
26PUBLIC    If exists and is set to 'True', the backend is considered "public".
27========= ====================================================================
28
29
30Backend functions
31-----------------
32
33======== =======================================================================
34Function Description
35======== =======================================================================
36<format> Called to generate the format- and backend-specific code for each of
37         the specified events. If the function does not exist, the backend is
38         considered not compatible with the given format.
39======== =======================================================================
40"""
41
42__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
43__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
44__license__    = "GPL version 2 or (at your option) any later version"
45
46__maintainer__ = "Stefan Hajnoczi"
47__email__      = "stefanha@linux.vnet.ibm.com"
48
49
50import os
51
52import tracetool
53
54
55def get_list(only_public = False):
56    """Get a list of (name, description) pairs."""
57    res = [("nop", "Tracing disabled.")]
58    modnames = []
59    for filename in os.listdir(tracetool.backend.__path__[0]):
60        if filename.endswith('.py') and filename != '__init__.py':
61            modnames.append(filename.rsplit('.', 1)[0])
62    for modname in modnames:
63        module = tracetool.try_import("tracetool.backend." + modname)
64
65        # just in case; should never fail unless non-module files are put there
66        if not module[0]:
67            continue
68        module = module[1]
69
70        public = getattr(module, "PUBLIC", False)
71        if only_public and not public:
72            continue
73
74        doc = module.__doc__
75        if doc is None:
76            doc = ""
77        doc = doc.strip().split("\n")[0]
78
79        name = modname.replace("_", "-")
80        res.append((name, doc))
81    return res
82
83
84def exists(name):
85    """Return whether the given backend exists."""
86    if len(name) == 0:
87        return False
88    if name == "nop":
89        return True
90    name = name.replace("-", "_")
91    return tracetool.try_import("tracetool.backend." + name)[1]
92
93
94def compatible(backend, format):
95    """Whether a backend is compatible with the given format."""
96    if not exists(backend):
97        raise ValueError("unknown backend: %s" % backend)
98
99    backend = backend.replace("-", "_")
100    format = format.replace("-", "_")
101
102    if backend == "nop":
103        return True
104    else:
105        func = tracetool.try_import("tracetool.backend." + backend,
106                                    format, None)[1]
107        return func is not None
108
109
110def _empty(events):
111    pass
112
113def generate(backend, format, events):
114    """Generate the per-event output for the given (backend, format) pair."""
115    if not compatible(backend, format):
116        raise ValueError("backend '%s' not compatible with format '%s'" %
117                         (backend, format))
118
119    backend = backend.replace("-", "_")
120    format = format.replace("-", "_")
121
122    if backend == "nop":
123        func = tracetool.try_import("tracetool.format." + format,
124                                    "nop", _empty)[1]
125    else:
126        func = tracetool.try_import("tracetool.backend." + backend,
127                                    format, None)[1]
128
129    func(events)
130