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