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
33All the following functions are optional, and no output will be generated if
34they do not exist.
35
36=============================== ==============================================
37Function                        Description
38=============================== ==============================================
39generate_<format>_begin(events) Generate backend- and format-specific file
40                                header contents.
41generate_<format>_end(events)   Generate backend- and format-specific file
42                                footer contents.
43generate_<format>(event)        Generate backend- and format-specific contents
44                                for the given event.
45=============================== ==============================================
46
47"""
48
49__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
50__copyright__  = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>"
51__license__    = "GPL version 2 or (at your option) any later version"
52
53__maintainer__ = "Stefan Hajnoczi"
54__email__      = "stefanha@linux.vnet.ibm.com"
55
56
57import os
58
59import tracetool
60
61
62def get_list(only_public = False):
63    """Get a list of (name, description) pairs."""
64    res = [("nop", "Tracing disabled.")]
65    modnames = []
66    for filename in os.listdir(tracetool.backend.__path__[0]):
67        if filename.endswith('.py') and filename != '__init__.py':
68            modnames.append(filename.rsplit('.', 1)[0])
69    for modname in sorted(modnames):
70        module = tracetool.try_import("tracetool.backend." + modname)
71
72        # just in case; should never fail unless non-module files are put there
73        if not module[0]:
74            continue
75        module = module[1]
76
77        public = getattr(module, "PUBLIC", False)
78        if only_public and not public:
79            continue
80
81        doc = module.__doc__
82        if doc is None:
83            doc = ""
84        doc = doc.strip().split("\n")[0]
85
86        name = modname.replace("_", "-")
87        res.append((name, doc))
88    return res
89
90
91def exists(name):
92    """Return whether the given backend exists."""
93    if len(name) == 0:
94        return False
95    if name == "nop":
96        return True
97    name = name.replace("-", "_")
98    return tracetool.try_import("tracetool.backend." + name)[1]
99
100
101class Wrapper:
102    def __init__(self, backends, format):
103        self._backends = [backend.replace("-", "_") for backend in backends]
104        self._format = format.replace("-", "_")
105        assert all(exists(backend) for backend in self._backends)
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):
116        self._run_function("generate_%s_begin", events)
117
118    def generate(self, event):
119        self._run_function("generate_%s", event)
120
121    def generate_end(self, events):
122        self._run_function("generate_%s_end", events)
123